Configuración Inicial
Importación de librerías
Para el desarrollo del análisis se requiere la carga de librerías
específicas para el manejo y transformación de datos, el trabajo con
fechas, la estimación de modelos bayesianos y la generación de
gráficos.
library(lubridate)
library(dplyr)
library(bayesreg)
library(MCMCpack)
library(tidyr)
library(cmdstanr)
library(brms)
library(broom)
library(tidybayes)
library(ggplot2)
library(ggdist)
library(bayesplot)
library(posterior)
library(plotly)
library(gridExtra)
library(scales)
library(rlang)
library(purrr)
Importación del dataset
Se define el directorio de trabajo y luego se importa el archivo que
contiene las series macroeconómicas utilizadas en el análisis.
setwd("G:/My Drive/TP EEA")
dataset <- read.csv("G:/My Drive/TP EEA/2025-09-QD.csv")
head(dataset)
gdppot <- read.csv("GDPPOT.csv")
head(gdppot)
Análisis Exploratorio
La Regla de Taylor es un modelo ampliamente utilizado en
macroeconomía para describir cómo debería reaccionar la política
monetaria ante desvíos de la inflación respecto de su meta y ante
fluctuaciones del producto respecto de su nivel potencial. Para
estimarla empíricamente, se requiere construir una serie de variables
macroeconómicas clave: el output gap, la inflación trimestral y
la brecha de inflación (inflation gap).
Selección de variables relevantes
En primer lugar, se construye un subconjunto del dataset original
conservando únicamente las series necesarias para el análisis. Las
principales variables macroeconómicas utilizadas son:
- PCECTPI — Índice de Precios de los Gastos en
Consumo Personal: indicador de inflación utilizado por la Reserva
Federal de Estados Unidos. Mide la evolución del nivel de precios de
bienes y servicios consumidos por los hogares.
- GDPC1 — Producto Bruto Interno Real: mide el nivel
de actividad económica ajustado por inflación y refleja la cantidad real
de bienes y servicios producidos en la economía.
- GDPPOT — Producto Potencial: representa el nivel de
producción que la economía podría sostener de manera sostenible, sin
generar presiones inflacionarias persistentes.
- FEDFUNDS — Tasa de Fondos Federales: tasa de
interés de referencia fijada por la Reserva Federal.
# 1) Producto (GDPC1 y GDPPOT) juntos
df_productos <- df_filtered %>%
dplyr::select(sasdate, GDPC1, GDPPOT) %>%
pivot_longer(cols = c(GDPC1, GDPPOT), names_to = "variable", values_to = "value")
p1 <- ggplot(df_productos, aes(x = sasdate, y = value, color = variable)) +
geom_line(size = 1) +
labs(title = "Producto Interno Bruto Real y Producto Potencial",
x = "Fecha",
y = "Valor") +
theme_minimal() +
theme(legend.title = element_blank())
# 2) Tasa de interés FEDFUNDS sola
df_tasa <- df_filtered %>%
dplyr::select(sasdate, FEDFUNDS)
p2 <- ggplot(df_tasa, aes(x = sasdate, y = FEDFUNDS)) +
geom_line(color = "steelblue", size = 1) +
labs(title = "Tasa de Fondos Federales (FEDFUNDS)",
x = "Fecha",
y = "Tasa (%)") +
theme_minimal()
# Mostrar los gráficos uno debajo del otro
grid.arrange(p1, p2, ncol = 1)

Output Gap
El output gap mide el desvío porcentual del Producto Interno Bruto
real (GDPC1) respecto de su nivel potencial (GDPPOT). La siguiente
transformación calcula esta brecha en puntos porcentuales:
df <- df %>%
mutate(
y_gap = 100 * (GDPC1 - GDPPOT) / GDPPOT)
# Seleccionamos la variable y pasamos a formato largo
df_long <- df %>%
dplyr::select(sasdate,y_gap) %>%
pivot_longer(cols = -sasdate, names_to = "variable", values_to = "value")
df_long <- df_long %>%
filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01") )
# Gráfico histórico
ggplot(df_long, aes(x = sasdate, y = value, color = variable)) +
geom_line(size = 1) +
facet_wrap(~variable, scales = "free_y", ncol = 2) +
labs(title = "Series historicas del y_gap",
x = "Fecha",
y = "Valor") +
theme_minimal()

Inflation Gap
La brecha de inflación mide el desvío entre la inflación observada y
la meta implícita de la Reserva Federal. Para este trabajo se utiliza un
objetivo anual del 2%, que en frecuencia trimestral equivale
aproximadamente a 0,5%. La variable pi_gap se define entonces como la
diferencia entre la inflación trimestral estimada a partir del índice
PCE y esta meta.
# Inflacion Trimestral objetivo
pi_star_q <- 0.5
# Extraemos del indice de precios la inflacion trimestral con la aproximacion log-diff
df <- df %>%
arrange(sasdate) %>%
mutate(
infl_q = 100 * (log(PCECTPI) - dplyr::lag(log(PCECTPI), 1)), # inflación trimestral en % (aprox log-diff)
pi_gap = infl_q - pi_star_q
) %>%
drop_na(pi_gap)
# Seleccionamos la variable y pasamos a formato largo
df_long <- df %>%
dplyr::select(sasdate,pi_gap) %>%
pivot_longer(cols = -sasdate, names_to = "variable", values_to = "value")
df_long <- df_long %>%
filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01") )
# Gráfico histórico
ggplot(df_long, aes(x = sasdate, y = value, color = variable)) +
geom_line(size = 1) +
facet_wrap(~variable, scales = "free_y", ncol = 2) +
labs(title = "Series historicas del desvio de la inflacion respecto a la objetiva",
x = "Fecha",
y = "Valor") +
theme_minimal()

Inercia de la tasa de interés
Para capturar el comportamiento gradual de la política monetaria, se
incorpora la tasa de fondos federales rezagada un período (i_lag1). Esta
variable refleja la inercia típica con la que la Reserva Federal ajusta
la tasa de interés, dado que los cambios suelen realizarse de manera
progresiva y no abrupta de un trimestre a otro.
# Contruimos las variables lags de interes y cambio en la tasa de interes
df <- df %>%
arrange(sasdate) %>%
mutate(
i_lag1 = dplyr::lag(FEDFUNDS, 1), # tasa rezagada 1
delta_i = FEDFUNDS - i_lag1 # cambio en la tasa
) %>%
drop_na(i_lag1, delta_i)
df_long <- df %>%
dplyr::select(sasdate, delta_i, FEDFUNDS) %>%
pivot_longer(cols = -sasdate, names_to = "variable", values_to = "value") %>%
filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01")) %>%
mutate(
variable = recode(variable,
FEDFUNDS = "FEDFUNDS",
delta_i = "Delta_i"),
variable = factor(variable, levels = c("FEDFUNDS", "Delta_i"))
)
ggplot(df_long, aes(x = sasdate, y = value, color = variable)) +
geom_line(size = 1) +
facet_wrap(~variable, scales = "free_y", nrow = 2) +
labs(
title = "Series históricas de la tasa de interés y su cambio respecto al trimestre anterior",
x = "Fecha",
y = "Valor",
color = "Variables"
) +
scale_color_manual(
values = c("FEDFUNDS" = "#1F77B4", "Delta_i" = "#FF7F0E"),
labels = c("FEDFUNDS" = "FEDFUNDS", "Delta_i" = "Delta_i")
) +
scale_y_continuous(labels = scales::label_number(accuracy = 0.1)) +
theme_minimal()

Análisis Estadisticos de las variables
En primer lugar, analizaremos las variables a través de sus medidas
de tendencia para el periodo en cuestión.
df_desc <- df %>% filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01") )
df_desc <- df_desc %>% dplyr::select(GDPC1, GDPPOT, FEDFUNDS, y_gap, infl_q, pi_gap, delta_i)
summary_stats <- df_desc %>%
summarise(
across(
everything(),
list(
min = ~min(. , na.rm = TRUE),
max = ~max(. , na.rm = TRUE),
mean = ~mean(. , na.rm = TRUE),
sd = ~sd(. , na.rm = TRUE)
),
.names = "{.col}_{.fn}"
)
) %>%
pivot_longer(
everything(),
names_to = c("variable", "stat"),
names_pattern = "(.*)_(.*)"
) %>%
pivot_wider(names_from = stat, values_from = value) %>%
mutate(across(where(is.numeric), ~round(. , 2)))
summary_stats
En segundo lugar, analizaremos la evolución de las variables desde el
enfoque histórico de las series de tiempo. Con el fin de representarlas
de manera conjunta en un mismo gráfico, recurrimos al proceso de
estandarización. Este procedimiento transforma cada observación en un
z‑score, es decir, en la cantidad de desviaciones estándar que dicho
valor se encuentra por encima o por debajo de la media de la variable.
De esta forma, las tres series quedan expresadas en una escala común, lo
que facilita la comparación de sus dinámicas a lo largo del tiempo.
# Seleccionamos las variables y pasamos a formato largo
df_norm <- df %>%
dplyr::select(sasdate, FEDFUNDS, pi_gap, y_gap) %>%
mutate(
FEDFUNDS_z = scale(FEDFUNDS),
pi_gap_z = scale(pi_gap),
y_gap_z = scale(y_gap)
) %>%
dplyr::select(sasdate, FEDFUNDS_z, pi_gap_z, y_gap_z) %>%
pivot_longer(
cols = -sasdate,
names_to = "variable",
values_to = "value"
) %>%
filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01") )
p <- ggplot(df_norm, aes(
x = sasdate,
y = value,
color = variable,
group = variable,
text = paste0(
"Fecha: ", format(sasdate, "%Y-%m"), "<br>",
"Variable: ", dplyr::recode(variable,
FEDFUNDS_z = "Tasa Fed",
pi_gap_z = "Inflation gap",
y_gap_z = "Output gap"), "<br>",
"Valor: ", sprintf("%.2f", value)
)
)) +
geom_line(size = 1.2) +
labs(
title = "Evolución comparada: tasa de la Fed y brechas (normalizadas)",
x = "Fecha",
y = "Valores normalizados (z-score)",
color = NULL
) +
scale_color_manual(
values = c(
FEDFUNDS_z = "#1F77B4",
pi_gap_z = "#AEC7E8",
y_gap_z = "#98DF8A"
),
labels = c("Tasa Fed", "Inflation gap", "Output gap")
) +
theme_minimal(base_size = 14) +
theme(
legend.position = "bottom",
legend.text = element_text(size = 9),
plot.title = element_text(face = "bold", size = 12, hjust = 0.5),
axis.title = element_text(face = "bold"),
axis.text = element_text(color = "gray30")
)
ggplotly(p, tooltip = "text") %>%
layout(
legend = list(
orientation = "h",
x = 0.2,
y = 0.1
)
)
Regresiones
OLS
Se determina una ventana temporal y se procede con la regresión
tradicional.
df_reg_sub <- df %>%
filter(sasdate > as.Date("1980-01-01") & sasdate < as.Date("2007-01-01") )
taylor_ols <- lm(
FEDFUNDS ~ i_lag1 + pi_gap + y_gap,
data = df_reg_sub
)
summary(taylor_ols)
##
## Call:
## lm(formula = FEDFUNDS ~ i_lag1 + pi_gap + y_gap, data = df_reg_sub)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.0362 -0.2918 0.0126 0.2851 5.1733
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.50005 0.19319 2.588 0.011024 *
## i_lag1 0.88716 0.03250 27.296 < 2e-16 ***
## pi_gap 0.89037 0.22647 3.932 0.000152 ***
## y_gap 0.16600 0.04975 3.337 0.001176 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.9141 on 104 degrees of freedom
## Multiple R-squared: 0.9401, Adjusted R-squared: 0.9384
## F-statistic: 544.4 on 3 and 104 DF, p-value: < 2.2e-16
La estimación OLS de la Regla de Taylor arroja un coeficiente de
inercia elevado para la tasa de interés (i_lag1 ≈ 0,89), lo que indica
que la Reserva Federal ajusta la política monetaria de manera gradual.
Tanto la brecha de inflación (pi_gap ≈ 0,89) como el output gap (y_gap ≈
0,17) presentan signos positivos y son estadísticamente significativos,
en línea con la idea de que la tasa de fondos federales aumenta cuando
la inflación se ubica por encima de la meta y cuando la actividad se
sitúa por encima de su nivel potencial. El modelo exhibe un muy buen
ajuste (R² ≈ 0,94), por lo que la especificación estimada captura
razonablemente bien el comportamiento histórico de la política monetaria
en el período considerado.
Regresión Bayesiana #1 - Priors Débiles
Además de la estimación mediante Mínimos Cuadrados Ordinarios, se
implementó una versión bayesiana de la Regla de Taylor. Este enfoque
permite combinar la información presente en los datos con conocimiento
previo sobre el comportamiento típico de la política monetaria. Para
esta primera especificación se utilizaron priors informativas basadas en
estimaciones reportadas en estudios del BIS, que reflejan valores
típicos para la inercia monetaria y las respuestas a inflación y
actividad económica.
priors_v1 <- c(
prior(normal(0, 5), class = "Intercept"),
prior(normal(0.74, 2), class = "b", coef = "i_lag1"),
prior(normal(2.11, 2), class = "b", coef = "pi_gap"),
prior(normal(0.26, 2), class = "b", coef = "y_gap"),
# Prior débil para sigma (desvío estándar residual)
prior(student_t(3, 0, 10), class = "sigma")
)
set.seed(42)
taylor_bayes_v1_brms <- brm(
FEDFUNDS ~ i_lag1 + pi_gap + y_gap,
data = df_reg_sub,
family = gaussian(),
prior = priors_v1,
chains = 4,
iter = 15000, # total draws por cadena
warmup = 5000, # burn-in
cores = 4,
seed = 42,
sample_prior = "yes"
)
summary(taylor_bayes_v1_brms)
## Family: gaussian
## Links: mu = identity
## Formula: FEDFUNDS ~ i_lag1 + pi_gap + y_gap
## Data: df_reg_sub (Number of observations: 108)
## Draws: 4 chains, each with iter = 15000; warmup = 5000; thin = 1;
## total post-warmup draws = 40000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept 0.50 0.20 0.11 0.89 1.00 39166 32860
## i_lag1 0.89 0.03 0.82 0.95 1.00 33831 29398
## pi_gap 0.90 0.23 0.46 1.35 1.00 35069 31239
## y_gap 0.17 0.05 0.07 0.26 1.00 43577 28867
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 0.93 0.07 0.81 1.06 1.00 45642 29975
##
## Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
Los resultados bayesianos con priors débiles son muy similares a los
de OLS: los coeficientes de inercia, inflación y output gap mantienen
magnitudes casi idénticas y continúan siendo claramente significativos.
Los intervalos al 95% reflejan la misma información que los intervalos
de confianza clásicos, indicando que las priors no alteran
sustancialmente la estimación. En síntesis, el modelo bayesiano
reproduce de manera consistente la estructura obtenida por OLS.
Regresión Bayesiana #2 - Priors Fuertes
En esta segunda especificación se mantiene la misma estructura del
modelo, pero se reemplazan las priors débiles por priors mucho más
concentradas, basadas en estimaciones del BIS. Esto permite evaluar
cuánto influyen las creencias previas en los coeficientes de la Regla de
Taylor, forzando al modelo a comenzar desde valores muy específicos para
la inercia monetaria, la respuesta a la inflación y la respuesta al
ciclo.
priors_v2 <- c(
prior(normal(0, 5.0), class = "Intercept"),
prior(normal(0.74, 0.10), class = "b", coef = "i_lag1"),
prior(normal(2.11, 0.10), class = "b", coef = "pi_gap"),
prior(normal(0.26, 0.05), class = "b", coef = "y_gap"),
# Prior débil para sigma (análogo a inv-gamma muy plana en sigma^2)
prior(student_t(3, 0, 10), class = "sigma")
)
set.seed(42)
taylor_bayes_v2_brms <- brm(
FEDFUNDS ~ i_lag1 + pi_gap + y_gap,
data = df_reg_sub,
family = gaussian(),
prior = priors_v2,
chains = 4,
iter = 15000,
warmup = 5000,
cores = 4,
seed = 42,
sample_prior = "yes"
)
summary(taylor_bayes_v2_brms)
## Family: gaussian
## Links: mu = identity
## Formula: FEDFUNDS ~ i_lag1 + pi_gap + y_gap
## Data: df_reg_sub (Number of observations: 108)
## Draws: 4 chains, each with iter = 15000; warmup = 5000; thin = 1;
## total post-warmup draws = 40000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept 0.85 0.19 0.47 1.23 1.00 45059 32471
## i_lag1 0.79 0.03 0.74 0.85 1.00 40639 31120
## pi_gap 1.95 0.09 1.76 2.13 1.00 41106 32861
## y_gap 0.22 0.04 0.15 0.30 1.00 45001 32105
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 1.01 0.07 0.88 1.17 1.00 42290 31769
##
## Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
Los resultados con priors fuertes muestran coeficientes claramente
influenciados por la información previa: la respuesta a la inflación
aumenta de manera marcada (≈ 1.95), mientras que la inercia monetaria se
reduce (≈ 0.79), moviéndose ambos en dirección a los valores fijados en
las priors. El output gap también presenta un coeficiente mayor (≈
0.22). Todos los parámetros resultan estadísticamente significativos
reflejando la mayor precisión impuesta por las priors. En conjunto, esta
versión del modelo ilustra cómo priors más concentradas pueden modificar
sustancialmente las estimaciones.
Análisis Gráfico
1) Forest plot
El gráfico compara los coeficientes estimados por OLS con las
distribuciones posteriores obtenidas bajo los modelos bayesianos con
priors débiles y fuertes. Se observa que, mientras la versión con priors
débiles reproduce casi exactamente los valores de OLS, las priors
fuertes desplazan las distribuciones hacia los valores impuestos por la
información previa, especialmente en la respuesta a la inflación. Esto
permite visualizar de manera directa cómo el peso de las priors afecta
la estimación de cada parámetro.
# i) Coeficientes OLS
ols_tidy <- broom::tidy(taylor_ols, conf.int = TRUE) %>%
filter(term != "(Intercept)") %>%
mutate(model = "OLS")
# ii) Coeficientes Bayes: draws de brms
b1_draws <- taylor_bayes_v1_brms %>%
spread_draws(b_i_lag1, b_pi_gap, b_y_gap) %>%
dplyr::select(b_i_lag1, b_pi_gap, b_y_gap) %>%
pivot_longer(cols = everything(),
names_to = "term",
values_to = "value") %>%
mutate(model = "Modelo con priors débiles")
b2_draws <- taylor_bayes_v2_brms %>%
spread_draws(b_i_lag1, b_pi_gap, b_y_gap) %>%
dplyr::select(b_i_lag1, b_pi_gap, b_y_gap) %>%
pivot_longer(cols = everything(),
names_to = "term",
values_to = "value") %>%
mutate(model = "Modelo con priors fuertes")
bayes_draws <- bind_rows(b1_draws, b2_draws) %>%
mutate(term = recode(term,
b_i_lag1 = "i_lag1 (rho)",
b_pi_gap = "pi_gap (phi_pi)",
b_y_gap = "y_gap (phi_y)"))
ols_tidy <- ols_tidy %>%
mutate(term = recode(term,
i_lag1 = "i_lag1 (rho)",
pi_gap = "pi_gap (phi_pi)",
y_gap = "y_gap (phi_y)"))
# iii) Gráfico combinado
ggplot(bayes_draws, aes(x = value, y = term, fill = model)) +
stat_halfeye(alpha = 0.7, point_interval = median_qi, .width = 0.95) +
geom_point(data = ols_tidy, aes(x = estimate, y = term),
inherit.aes = FALSE, shape = 21, size = 2.2, fill = "white") +
geom_errorbarh(data = ols_tidy,
aes(xmin = conf.low, xmax = conf.high, y = term),
inherit.aes = FALSE, height = 0.15) +
labs(x = "Valor del coeficiente", y = NULL,
title = "OLS vs Bayes",
subtitle = "Distribuciones posteriores y IC OLS") +
theme_minimal()

2) Prior vs Posterior (para #1 y #2)
El gráfico muestra cómo se comparan las distribuciones prior y
posterior en ambos modelos. Con priors débiles, los datos modifican
fuertemente la distribución posterior. Con priors fuertes, la posterior
permanece muy cerca de la prior, indicando que la información previa
tiene mucho más peso en la estimación.
pars <- c("b_i_lag1", "b_pi_gap", "b_y_gap")
make_prior_post_long <- function(fit, label){
prior_df <- prior_draws(fit) %>%
as_draws_df() %>%
dplyr::select(all_of(pars)) %>%
pivot_longer(everything(), names_to = "term", values_to = "value") %>%
mutate(type = "Prior", model = label)
post_df <- as_draws_df(fit) %>%
dplyr::select(all_of(pars)) %>%
pivot_longer(everything(), names_to = "term", values_to = "value") %>%
mutate(type = "Posterior", model = label)
bind_rows(prior_df, post_df)
}
df_v1 <- make_prior_post_long(taylor_bayes_v1_brms, "Priors débiles")
df_v2 <- make_prior_post_long(taylor_bayes_v2_brms, "Priors fuertes")
df_all <- bind_rows(df_v1, df_v2) %>%
mutate(
term = recode(term,
b_i_lag1 = "i_lag1 (rho)",
b_pi_gap = "pi_gap (phi_pi)",
b_y_gap = "y_gap (phi_y)"),
term = factor(term, levels = c("i_lag1 (rho)", "pi_gap (phi_pi)", "y_gap (phi_y)"))
)
ggplot(df_all, aes(x = value, y = term, fill = type)) +
stat_halfeye(alpha = 0.6, position = "identity",
point_interval = median_qi, .width = 0.95) +
facet_wrap(~model) +
coord_cartesian(xlim = c(-1, 4)) +
labs(
title = "Prior vs Posterior por modelo",
subtitle = "Comparación visual para priors débiles y fuertes",
x = "Valor del coeficiente", y = NULL
) +
theme_minimal()

3) Comparación Predictiva: Fitted vs actual
El gráfico compara la tasa observada con las predicciones obtenidas
por OLS y por los modelos bayesianos con priors débiles y fuertes. En
ambos casos, las predicciones bayesianas siguen muy de cerca la
trayectoria histórica de la tasa de fondos federales, y las bandas
creíbles (50% y 95%) son estrechas, indicando buena precisión del
modelo. Las priors fuertes producen intervalos ligeramente más
concentrados, reflejando mayor peso de la información previa.
df_plot <- df_reg_sub %>%
mutate(fit_ols = predict(taylor_ols, newdata = df_reg_sub))
pred_v1 <- df_reg_sub %>%
add_epred_draws(taylor_bayes_v1_brms, ndraws = 2000)
pred_v2 <- df_reg_sub %>%
add_epred_draws(taylor_bayes_v2_brms, ndraws = 2000)
summ_pred <- function(pred_df, label){
pred_df %>%
group_by(sasdate) %>%
median_qi(.epred, .width = c(0.5, 0.95)) %>%
mutate(model = label)
}
p1 <- summ_pred(pred_v1, "Bayes priors débiles")
p2 <- summ_pred(pred_v2, "Bayes priors fuertes")
pred_bands <- bind_rows(p1, p2)
ggplot(df_plot, aes(x = sasdate, y = FEDFUNDS)) +
geom_line(color = "black") +
geom_line(aes(y = fit_ols), linetype = "dashed") +
stat_lineribbon(data = pred_bands,
aes(y = .epred, ymin = .lower, ymax = .upper, fill = model),
alpha = 0.25) +
facet_wrap(~model, ncol = 1) +
labs(title = "Predicción: OLS vs Bayes",
subtitle = "Bandas creíbles 50% y 95%",
y = "FEDFUNDS", x = NULL) +
theme_minimal()

4) Distribucion de reacción a inflación
La figura muestra la distribución posterior del parámetro que mide la
respuesta de la tasa de interés a la inflación (ϕπ) bajo ambos conjuntos
de priors. Con priors débiles, la distribución es más dispersa y
centrada alrededor de valores cercanos a 1, mientras que con priors
fuertes se concentra en torno al benchmark de 2.11 propuesto por el BIS
(línea punteada). Esto ilustra cómo la información previa influye en la
magnitud estimada de la reacción de política monetaria.
b1_phi_pi <- as_draws_df(taylor_bayes_v1_brms)$b_pi_gap
b2_phi_pi <- as_draws_df(taylor_bayes_v2_brms)$b_pi_gap
df_phi <- tibble(
value = c(b1_phi_pi, b2_phi_pi),
model = rep(c("Priors débiles","Priors fuertes"),
c(length(b1_phi_pi), length(b2_phi_pi)))
)
ggplot(df_phi, aes(x = value, fill = model)) +
geom_density(alpha = 0.5) +
geom_vline(
xintercept = 2.11,
linetype = "dotted",
linewidth = 1.2,
color = "black",
alpha = 0.9
) +
labs(title = "Respuesta a inflación (phi_pi)",
subtitle = "Línea punteada = benchmark BIS",
x = expression(phi[pi]), y = "Densidad") +
theme_minimal()

5) Stacked PPC
Los gráficos PPC permiten evaluar si los modelos bayesianos pueden
reproducir la distribución observada de la tasa de interés. Tanto el
modelo con priors débiles como el de priors fuertes generan
distribuciones simuladas coherentes con los datos reales, lo que indica
un ajuste adecuado.
pp_check(taylor_bayes_v1_brms,
type = "dens_overlay",
ndraws = 50) +
ggtitle("PPC - Priors Débiles") +
labs(x = "FEDFUNDS", y = "Densidad") +
scale_y_continuous(expand = expansion(mult = c(0, 0.05))) +
theme_minimal(base_size = 12)

pp_check(taylor_bayes_v2_brms,
type = "dens_overlay",
ndraws = 50) +
ggtitle("PPC - Priors Fuertes") +
labs(x = "FEDFUNDS", y = "Densidad") +
scale_y_continuous(expand = expansion(mult = c(0, 0.05))) +
theme_minimal(base_size = 12)

Bayesian Lasso
En esta sección se extiende la estimación de la Regla de Taylor
incorporando un conjunto de variables macroeconómicas adicionales
(controles). Para evitar sobreajuste y permitir que el propio modelo
determine cuáles de estos controles son realmente relevantes, se utiliza
un enfoque bayesiano con un prior tipo LASSO (distribución Laplace), que
induce shrinkage sobre todos los coeficientes adicionales. Los
coeficientes centrales de la Regla de Taylor —inercia, brecha de
inflación y output gap— se mantienen con priors informativos fuertes
asegurando que LASSO actúe únicamente sobre los controles. Este enfoque
permite evaluar simultáneamente la robustez de la regla y el aporte
marginal de variables macroeconómicas adicionales. Los controles que
estaremos usando son los siguientes:
- TCU: Capacity Utilization: Total Industry (Percent
of Capacity)
- USGOVT: All Employees: Government (Thousands of
Persons)
- UNRATE: Civilian Unemployment Rate (Percent)
- DGDSRG3Q086SBEA: Personal consumption expenditures:
Goods (chain-type price index)
- GS10TB3Mx: 10-Year Treasury Constant Maturity Minus
3-Month Treasury Bill, secondary market (Percent)
- CPF3MTB3Mx: 3-Month Commercial Paper Minus 3-Month
Treasury Bill, secondary market (Percent)
- BOGMBASEREALx: St. Louis Adjusted Monetary Base
(Billions of 1982-84 Dollars), deflated by CPI
controls <- c("TCU","USGOVT","UNRATE","DGDSRG3Q086SBEA",
"GS10TB3Mx","CPF3MTB3Mx","BOGMBASEREALx")
# Estandarizamos variables de control
df_reg_sub <- df_reg_sub %>%
mutate(across(all_of(controls), ~ as.numeric(scale(.x))))
# Fórmula
form_v3 <- bf( FEDFUNDS ~ i_lag1 + pi_gap + y_gap + TCU + USGOVT + UNRATE + DGDSRG3Q086SBEA + GS10TB3Mx + CPF3MTB3Mx + BOGMBASEREALx )
priors_v3 <- c(
# Intercepto
prior(normal(0, 5.0), class = "Intercept"),
# LASSO general para todos los betas - equivale a 1/lambda, así que si ->0 mayor es la penalización (shrinkage)
prior(double_exponential(0, 0.2), class = "b"),
# Núcleo BIS con priors normales fuertes
prior(normal(0.74, 0.10), class = "b", coef = "i_lag1"),
prior(normal(2.11, 0.10), class = "b", coef = "pi_gap"),
prior(normal(0.26, 0.05), class = "b", coef = "y_gap"),
# Sigma débil
prior(student_t(3, 0, 10), class = "sigma")
)
# Ajuste
set.seed(42)
taylor_bayes_v3_brms <- brm(
formula = form_v3,
data = df_reg_sub,
family = gaussian(),
prior = priors_v3,
chains = 4,
iter = 15000,
warmup = 5000,
cores = 4,
seed = 42,
sample_prior = "yes"
)
summary(taylor_bayes_v3_brms)
## Family: gaussian
## Links: mu = identity
## Formula: FEDFUNDS ~ i_lag1 + pi_gap + y_gap + TCU + USGOVT + UNRATE + DGDSRG3Q086SBEA + GS10TB3Mx + CPF3MTB3Mx + BOGMBASEREALx
## Data: df_reg_sub (Number of observations: 108)
## Draws: 4 chains, each with iter = 15000; warmup = 5000; thin = 1;
## total post-warmup draws = 40000
##
## Regression Coefficients:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept 1.98 0.35 1.28 2.67 1.00 29664 27505
## i_lag1 0.62 0.05 0.52 0.73 1.00 29521 27363
## pi_gap 1.88 0.10 1.69 2.07 1.00 42749 29402
## y_gap 0.25 0.05 0.16 0.34 1.00 40189 28194
## TCU -0.08 0.12 -0.33 0.14 1.00 31117 26653
## USGOVT -0.43 0.33 -1.14 0.09 1.00 22040 22937
## UNRATE 0.33 0.20 -0.02 0.73 1.00 31428 27282
## DGDSRG3Q086SBEA 0.17 0.21 -0.16 0.64 1.00 29687 23267
## GS10TB3Mx -0.48 0.14 -0.74 -0.21 1.00 28764 27334
## CPF3MTB3Mx 0.08 0.11 -0.12 0.31 1.00 37471 25324
## BOGMBASEREALx -0.15 0.22 -0.63 0.24 1.00 30530 24019
##
## Further Distributional Parameters:
## Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma 0.89 0.07 0.76 1.03 1.00 33692 29176
##
## Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
La estimación bayesiana con prior LASSO muestra que los coeficientes
principales de la Regla de Taylor (inercia, brecha de inflación y output
gap) se mantienen significativos y con magnitudes consistentes con las
versiones anteriores. En cambio, la mayoría de las variables de control
presentan distribuciones posteriores centradas cerca de cero y con
intervalos amplios, indicando que el shrinkage penaliza fuertemente su
aporte marginal. Solo GS10TB3Mx muestra evidencia moderada de efecto. En
conjunto, el modelo confirma que la dinámica de tasas está explicada
casi por completo por los componentes centrales de la regla.
Visualización de Resultados
# Visualizacion de controles
controls_b <- c("b_TCU","b_USGOVT","b_UNRATE","b_DGDSRG3Q086SBEA",
"b_GS10TB3Mx","b_CPF3MTB3Mx","b_BOGMBASEREALx")
as_draws_df(taylor_bayes_v3_brms) %>%
dplyr::select(all_of(controls_b)) %>%
pivot_longer(everything(), names_to="term", values_to="value") %>%
ggplot(aes(x=value, y=term)) +
stat_halfeye(.width = 0.95) +
geom_vline(xintercept=0, linetype="dashed") +
labs(title="Controles con prior LASSO: posterior",
subtitle="Los que quedan concentrados en 0 no aportan",
x="Coeficiente", y=NULL) +
theme_minimal()

Este gráfico muestra la distribución posterior de los coeficientes
asociados a las variables de control bajo el prior LASSO. Las
distribuciones que quedan concentradas alrededor de cero indican que,
dado el shrinkage aplicado, esas variables no aportan información
relevante.
# Comparación de Lambdas
# grilla de scales (b): de débil a fuerte
b_grid <- c(1.0, 0.7, 0.5, 0.3, 0.2, 0.15, 0.1, 0.07, 0.05, 0.025)
# Funcion que arma priors con cada b
make_priors_v3 <- function(b_scale){
laplace_str <- paste0("double_exponential(0, ", b_scale, ")")
c(
# Intercepto
set_prior("normal(0, 5.0)", class = "Intercept"),
# LASSO general para todos los coeficientes b
set_prior(laplace_str, class = "b"),
# Sobrescribo núcleo BIS con normales fuertes
set_prior("normal(0.74, 0.10)", class = "b", coef = "i_lag1"),
set_prior("normal(2.11, 0.10)", class = "b", coef = "pi_gap"),
set_prior("normal(0.26, 0.05)", class = "b", coef = "y_gap"),
# sigma débil
set_prior("student_t(3, 0, 10)", class = "sigma")
)
}
# Reestimar modelos para cada b
fits_v3 <- map(b_grid, ~ brm(
formula = form_v3,
data = df_reg_sub,
family = gaussian(),
prior = make_priors_v3(.x),
chains = 4,
iter = 4000,
warmup = 1000,
cores = 4,
seed = 42,
refresh = 0
))
names(fits_v3) <- paste0("b_", b_grid)
# Extraer cofiecientes de controles y construir el path
core_vars <- c("i_lag1", "pi_gap", "y_gap")
core_b <- paste0("b_", core_vars)
# obtiene nombres b_ reales desde cualquier fit brms
get_controls_b <- function(fit) {
b_names <- grep("^b_", posterior::variables(as_draws_df(fit)), value = TRUE)
setdiff(b_names, core_b)
}
controls_b <- get_controls_b(fits_v3[[1]]) # usar el primer fit como referencia
controls_b
# función para extraer el coeficiente "moda" del vector
get_mode <- function(x) {
d <- density(x)
d$x[which.max(d$y)]
}
paths_df_map <- map2_dfr(fits_v3, b_grid, ~ {
# extraer draws de los coeficientes de controles
draws <- as_draws_df(.x) %>%
dplyr::select(all_of(controls_b)) %>%
pivot_longer(everything(), names_to="term", values_to="value") %>%
# excluir intercepto
filter(term != "b_Intercept") %>%
group_by(term) %>%
summarise(
map = get_mode(value),
.groups="drop"
)
draws %>%
mutate(
b_scale = .y,
log_lambda = log(1/.y) # lambda clásica = 1/b
)
})
# Graficar coeficient path con MAP (sin intercepto)
ggplot(paths_df_map, aes(x = log_lambda, y = map, color = term)) +
geom_line(linewidth = 0.9) +
geom_hline(yintercept = 0, linetype = "dashed") +
labs(
title = "Coeficient paths para controles (v3)",
subtitle = "A mayor log(lambda) = mayor shrinkage (b más chico)",
x = "log(lambda) [lambda = 1 / b_scale]",
y = "Moda posterior del coeficiente"
) +
theme_minimal() +
theme(legend.title = element_blank())

En este caso, se puede ver cómo cambian los coeficientes de las
variables de control a medida que aumenta la penalización LASSO. A
medida que el shrinkage se intensifica, todos los coeficientes se
contraen progresivamente hacia cero. Las variables cuyos coeficientes
caen rápidamente indican menor relevancia explicativa, mientras que las
que resisten más tiempo alejadas de cero son las que el modelo considera
relativamente más informativas.
LS0tDQp0aXRsZTogIkluZmVyZW5jaWEgQmF5ZXNpYW5hIGFwbGljYWRhIGEgSGlww7N0ZXNpcyBNYWNyb2Vjb27Ds21pY2FzIg0KYXV0aG9yOiAiUGVkcm8gQm9zY2gsIE5pY29sYXMgQ2FyaWNhdGksIEFndXN0w61uIFJpdmFzIg0KZGF0ZTogIjIwLzExLzIwMjUiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0Kc3VidGl0bGU6IFRQIOKAkyBFbmZvcXVlIEVzdGFkw61zdGljbyBkZWwgQXByZW5kaXphamUNCi0tLQ0KDQojIE9iamV0aXZvDQoNCkVsIG9iamV0aXZvIGRlIGVzdGUgaW5mb3JtZSBlcyBlc3RpbWFyIGxhIHJlZ2xhIGRlIFRheWxvciB1dGlsaXphbmRvIG3DqXRvZG9zIHRyYWRpY2lvbmFsZXMgKE9MUykgeSBtb2RlbG9zIGJheWVzaWFub3MuIFBhcmEgbGEgZXNwZWNpZmljYWNpw7NuIGRlIGxvcyBwcmlvcnMgeSBjaWVydG9zIHBhcsOhbWV0cm9zIGRlIHJlZmVyZW5jaWEgc2UgdXRpbGl6YW4gdmFsb3JlcyBkb2N1bWVudGFkb3MgZW4gZGlzdGludG9zIHRyYWJham9zIGFjYWTDqW1pY29zLCBlbiBwYXJ0aWN1bGFyIHVuIGFydMOtY3VsbyBkZWwgQklTIChCYW5rIGZvciBJbnRlcm5hdGlvbmFsIFNldHRsZW1lbnRzKSwgcXVlIHByZXNlbnRhIGluZm9ybWFjacOzbiBhY2VyY2EgZGUgcG9sw610aWNhIG1vbmV0YXJpYS4NCg0KIyBDb25maWd1cmFjacOzbiBJbmljaWFsDQoNCiMjIEltcG9ydGFjacOzbiBkZSBsaWJyZXLDrWFzDQoNClBhcmEgZWwgZGVzYXJyb2xsbyBkZWwgYW7DoWxpc2lzIHNlIHJlcXVpZXJlIGxhIGNhcmdhIGRlIGxpYnJlcsOtYXMgZXNwZWPDrWZpY2FzIHBhcmEgZWwgbWFuZWpvIHkgdHJhbnNmb3JtYWNpw7NuIGRlIGRhdG9zLCBlbCB0cmFiYWpvIGNvbiBmZWNoYXMsIGxhIGVzdGltYWNpw7NuIGRlIG1vZGVsb3MgYmF5ZXNpYW5vcyB5IGxhIGdlbmVyYWNpw7NuIGRlIGdyw6FmaWNvcy4NCg0KYGBge3IgbGliLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShiYXllc3JlZykgICANCmxpYnJhcnkoTUNNQ3BhY2spDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShjbWRzdGFucikNCmxpYnJhcnkoYnJtcykNCmxpYnJhcnkoYnJvb20pDQpsaWJyYXJ5KHRpZHliYXllcykNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2dkaXN0KQ0KbGlicmFyeShiYXllc3Bsb3QpDQpsaWJyYXJ5KHBvc3RlcmlvcikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KHNjYWxlcykNCmxpYnJhcnkocmxhbmcpDQpsaWJyYXJ5KHB1cnJyKQ0KYGBgDQoNCiMjIEltcG9ydGFjacOzbiBkZWwgZGF0YXNldA0KDQpTZSBkZWZpbmUgZWwgZGlyZWN0b3JpbyBkZSB0cmFiYWpvIHkgbHVlZ28gc2UgaW1wb3J0YSBlbCBhcmNoaXZvIHF1ZSBjb250aWVuZSBsYXMgc2VyaWVzIG1hY3JvZWNvbsOzbWljYXMgdXRpbGl6YWRhcyBlbiBlbCBhbsOhbGlzaXMuDQoNCmBgYHtyIGltcH0NCnNldHdkKCJHOi9NeSBEcml2ZS9UUCBFRUEiKQ0KDQpkYXRhc2V0IDwtIHJlYWQuY3N2KCJHOi9NeSBEcml2ZS9UUCBFRUEvMjAyNS0wOS1RRC5jc3YiKQ0KDQpoZWFkKGRhdGFzZXQpDQoNCmdkcHBvdCA8LSByZWFkLmNzdigiR0RQUE9ULmNzdiIpDQoNCmhlYWQoZ2RwcG90KQ0KDQpgYGANCg0KIyMgVHJhbnNmb3JtYWNpw7NuIGRlIGRhdG9zDQpTZSByZWFsaXphbiBjb3JyZWNjaW9uZXMgbmVjZXNhcmlhcyBhbnRlcyBkZWwgYW7DoWxpc2lzIHkgc2UgbWVyZ2VhbiBsb3MgZGF0YXNldHMuDQpgYGB7ciB0cn0NCmRhdGFzZXQgPC0gZGF0YXNldFstYygxLCAyKSwgXSAgIyBTZSBlbGltaW5hbiBmaWxhcyBpbmljaWFsZXMNCmRhdGFzZXQkc2FzZGF0ZSA8LSBhcy5EYXRlKGRhdGFzZXQkc2FzZGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZIikgICMgQ29udmVyc2nDs24gYSBmZWNoYXMNCmRhdGFzZXQkcXVhcnRlcl9sYWJlbCA8LSBwYXN0ZTAoeWVhcihkYXRhc2V0JHNhc2RhdGUpLCAiUSIsIHF1YXJ0ZXIoZGF0YXNldCRzYXNkYXRlKSkgIyBFdGlxdWV0YSB0cmltZXN0cmFsDQpkYXRhc2V0IDwtIGRhdGFzZXRbb3JkZXIoZGF0YXNldCRzYXNkYXRlKSwgXSAgICMgT3JkZW4gdGVtcG9yYWwNCmRhdGFzZXQkdGltZV9pbmRleCA8LSBzZXFfbGVuKG5yb3coZGF0YXNldCkpICAgICMgw41uZGljZSBkZSB0aWVtcG8NCmRhdGFzZXQgPC0gZGF0YXNldCAlPiUgcmVsb2NhdGUocXVhcnRlcl9sYWJlbCwgdGltZV9pbmRleCwgLmFmdGVyID0gMSkgICMgUmVvcmdhbml6YWNpw7NuIGRlIGNvbHVtbmFzDQpgYGANCmBgYHtyIHRyMn0NCmdkcHBvdCRvYnNlcnZhdGlvbl9kYXRlIDwtIGdzdWIoIi0iLCAiLyIsIGdkcHBvdCRvYnNlcnZhdGlvbl9kYXRlKQ0KZ2RwcG90JG9ic2VydmF0aW9uX2RhdGUgPC0gYXMuRGF0ZShnZHBwb3Qkb2JzZXJ2YXRpb25fZGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZIikgIyBDb252ZXJzacOzbiBhIGZlY2hhcw0KDQpkYXRhc2V0IDwtIGRhdGFzZXQgJT4lDQogIGxlZnRfam9pbigNCiAgICBnZHBwb3QsDQogICAgYnkgPSBjKCJzYXNkYXRlIiA9ICJvYnNlcnZhdGlvbl9kYXRlIikNCiAgKQ0KDQogI1NlbGVjY2lvbm8gdmFyaWFibGVzDQpkZiA8LSBkYXRhc2V0ICU+JQ0KICBkcGx5cjo6c2VsZWN0KA0KICAgIHNhc2RhdGUsDQogICAgcXVhcnRlcl9sYWJlbCwNCiAgICB0aW1lX2luZGV4LA0KICAgIFBDRUNUUEksDQogICAgR0RQQzEsDQogICAgR0RQUE9ULA0KICAgIEZFREZVTkRTLA0KICAgIFRDVSwgI3ZhcmlhYmxlIGRlIGNvbnRyb2wNCiAgICBVU0dPVlQsICN2YXJpYWJsZSBkZSBjb250cm9sDQogICAgVU5SQVRFLCAjdmFyaWFibGUgZGUgY29udHJvbA0KICAgIERHRFNSRzNRMDg2U0JFQSwgI3ZhcmlhYmxlIGRlIGNvbnRyb2wNCiAgICBHUzEwVEIzTXgsICN2YXJpYWJsZSBkZSBjb250cm9sDQogICAgQ1BGM01UQjNNeCwgI3ZhcmlhYmxlIGRlIGNvbnRyb2wNCiAgICBCT0dNQkFTRVJFQUx4ICN2YXJpYWJsZSBkZSBjb250cm9sDQogICkNCg0KIyBGaWx0cmFyIGVsIHJhbmdvIGRlIGZlY2hhcyBwYXJhIGxhcyBzZXJpZXMNCmRmX2ZpbHRlcmVkIDwtIGRmICU+JQ0KICBmaWx0ZXIoc2FzZGF0ZSA+IGFzLkRhdGUoIjE5ODAtMDEtMDEiKSAmIHNhc2RhdGUgPCBhcy5EYXRlKCIyMDA3LTAxLTAxIikpDQoNCmhlYWQoZGZfZmlsdGVyZWQpDQpgYGANCg0KIyBBbsOhbGlzaXMgRXhwbG9yYXRvcmlvDQoNCkxhIFJlZ2xhIGRlIFRheWxvciBlcyB1biBtb2RlbG8gYW1wbGlhbWVudGUgdXRpbGl6YWRvIGVuIG1hY3JvZWNvbm9tw61hIHBhcmEgZGVzY3JpYmlyIGPDs21vIGRlYmVyw61hIHJlYWNjaW9uYXIgbGEgcG9sw610aWNhIG1vbmV0YXJpYSBhbnRlIGRlc3bDrW9zIGRlIGxhIGluZmxhY2nDs24gcmVzcGVjdG8gZGUgc3UgbWV0YSB5IGFudGUgZmx1Y3R1YWNpb25lcyBkZWwgcHJvZHVjdG8gcmVzcGVjdG8gZGUgc3Ugbml2ZWwgcG90ZW5jaWFsLiBQYXJhIGVzdGltYXJsYSBlbXDDrXJpY2FtZW50ZSwgc2UgcmVxdWllcmUgY29uc3RydWlyIHVuYSBzZXJpZSBkZSB2YXJpYWJsZXMgbWFjcm9lY29uw7NtaWNhcyBjbGF2ZTogZWwgKm91dHB1dCBnYXAqLCBsYSBpbmZsYWNpw7NuIHRyaW1lc3RyYWwgeSBsYSBicmVjaGEgZGUgaW5mbGFjacOzbiAoKmluZmxhdGlvbiBnYXAqKS4NCg0KIyMgU2VsZWNjacOzbiBkZSB2YXJpYWJsZXMgcmVsZXZhbnRlcw0KRW4gcHJpbWVyIGx1Z2FyLCBzZSBjb25zdHJ1eWUgdW4gc3ViY29uanVudG8gZGVsIGRhdGFzZXQgb3JpZ2luYWwgY29uc2VydmFuZG8gw7puaWNhbWVudGUgbGFzIHNlcmllcyBuZWNlc2FyaWFzIHBhcmEgZWwgYW7DoWxpc2lzLiBMYXMgcHJpbmNpcGFsZXMgdmFyaWFibGVzIG1hY3JvZWNvbsOzbWljYXMgdXRpbGl6YWRhcyBzb246DQoNCi0gKipQQ0VDVFBJKiog4oCUIMONbmRpY2UgZGUgUHJlY2lvcyBkZSBsb3MgR2FzdG9zIGVuIENvbnN1bW8gUGVyc29uYWw6IGluZGljYWRvciBkZSBpbmZsYWNpw7NuIHV0aWxpemFkbyBwb3IgbGEgUmVzZXJ2YSBGZWRlcmFsIGRlIEVzdGFkb3MgVW5pZG9zLiBNaWRlIGxhIGV2b2x1Y2nDs24gZGVsIG5pdmVsIGRlIHByZWNpb3MgZGUgYmllbmVzIHkgc2VydmljaW9zIGNvbnN1bWlkb3MgcG9yIGxvcyBob2dhcmVzLg0KLSAqKkdEUEMxKiog4oCUIFByb2R1Y3RvIEJydXRvIEludGVybm8gUmVhbDogbWlkZSBlbCBuaXZlbCBkZSBhY3RpdmlkYWQgZWNvbsOzbWljYSBhanVzdGFkbyBwb3IgaW5mbGFjacOzbiB5IHJlZmxlamEgbGEgY2FudGlkYWQgcmVhbCBkZSBiaWVuZXMgeSBzZXJ2aWNpb3MgcHJvZHVjaWRvcyBlbiBsYSBlY29ub23DrWEuDQotICoqR0RQUE9UKiog4oCUIFByb2R1Y3RvIFBvdGVuY2lhbDogcmVwcmVzZW50YSBlbCBuaXZlbCBkZSBwcm9kdWNjacOzbiBxdWUgbGEgZWNvbm9tw61hIHBvZHLDrWEgc29zdGVuZXIgZGUgbWFuZXJhIHNvc3RlbmlibGUsIHNpbiBnZW5lcmFyIHByZXNpb25lcyBpbmZsYWNpb25hcmlhcyBwZXJzaXN0ZW50ZXMuDQotICoqRkVERlVORFMqKiDigJQgVGFzYSBkZSBGb25kb3MgRmVkZXJhbGVzOiB0YXNhIGRlIGludGVyw6lzIGRlIHJlZmVyZW5jaWEgZmlqYWRhIHBvciBsYSBSZXNlcnZhIEZlZGVyYWwuDQpgYGB7ciBzZWxlY3RfdmFycywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KIyAxKSBQcm9kdWN0byAoR0RQQzEgeSBHRFBQT1QpIGp1bnRvcw0KZGZfcHJvZHVjdG9zIDwtIGRmX2ZpbHRlcmVkICU+JQ0KICBkcGx5cjo6c2VsZWN0KHNhc2RhdGUsIEdEUEMxLCBHRFBQT1QpICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGMoR0RQQzEsIEdEUFBPVCksIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbHVlIikNCg0KcDEgPC0gZ2dwbG90KGRmX3Byb2R1Y3RvcywgYWVzKHggPSBzYXNkYXRlLCB5ID0gdmFsdWUsIGNvbG9yID0gdmFyaWFibGUpKSArDQogIGdlb21fbGluZShzaXplID0gMSkgKw0KICBsYWJzKHRpdGxlID0gIlByb2R1Y3RvIEludGVybm8gQnJ1dG8gUmVhbCB5IFByb2R1Y3RvIFBvdGVuY2lhbCIsDQogICAgICAgeCA9ICJGZWNoYSIsDQogICAgICAgeSA9ICJWYWxvciIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQ0KDQojIDIpIFRhc2EgZGUgaW50ZXLDqXMgRkVERlVORFMgc29sYQ0KZGZfdGFzYSA8LSBkZl9maWx0ZXJlZCAlPiUNCiAgZHBseXI6OnNlbGVjdChzYXNkYXRlLCBGRURGVU5EUykNCg0KcDIgPC0gZ2dwbG90KGRmX3Rhc2EsIGFlcyh4ID0gc2FzZGF0ZSwgeSA9IEZFREZVTkRTKSkgKw0KICBnZW9tX2xpbmUoY29sb3IgPSAic3RlZWxibHVlIiwgc2l6ZSA9IDEpICsNCiAgbGFicyh0aXRsZSA9ICJUYXNhIGRlIEZvbmRvcyBGZWRlcmFsZXMgKEZFREZVTkRTKSIsDQogICAgICAgeCA9ICJGZWNoYSIsDQogICAgICAgeSA9ICJUYXNhICglKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgTW9zdHJhciBsb3MgZ3LDoWZpY29zIHVubyBkZWJham8gZGVsIG90cm8NCmdyaWQuYXJyYW5nZShwMSwgcDIsIG5jb2wgPSAxKQ0KDQpgYGANCg0KIyMgT3V0cHV0IEdhcA0KRWwgb3V0cHV0IGdhcCBtaWRlIGVsIGRlc3bDrW8gcG9yY2VudHVhbCBkZWwgUHJvZHVjdG8gSW50ZXJubyBCcnV0byByZWFsIChHRFBDMSkgcmVzcGVjdG8gZGUgc3Ugbml2ZWwgcG90ZW5jaWFsIChHRFBQT1QpLiBMYSBzaWd1aWVudGUgdHJhbnNmb3JtYWNpw7NuIGNhbGN1bGEgZXN0YSBicmVjaGEgZW4gcHVudG9zIHBvcmNlbnR1YWxlczoNCmBgYHtyIG91dHB1dF9nYXB9DQpkZiA8LSBkZiAlPiUNCiAgbXV0YXRlKA0KICAgIHlfZ2FwID0gMTAwICogKEdEUEMxIC0gR0RQUE9UKSAvIEdEUFBPVCkNCg0KDQojIFNlbGVjY2lvbmFtb3MgbGEgdmFyaWFibGUgeSBwYXNhbW9zIGEgZm9ybWF0byBsYXJnbw0KZGZfbG9uZyA8LSBkZiAlPiUNCiAgZHBseXI6OnNlbGVjdChzYXNkYXRlLHlfZ2FwKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtc2FzZGF0ZSwgbmFtZXNfdG8gPSAidmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQ0KDQpkZl9sb25nIDwtIGRmX2xvbmcgJT4lDQogIGZpbHRlcihzYXNkYXRlID4gYXMuRGF0ZSgiMTk4MC0wMS0wMSIpICYgc2FzZGF0ZSA8IGFzLkRhdGUoIjIwMDctMDEtMDEiKSApDQoNCiMgR3LDoWZpY28gaGlzdMOzcmljbw0KZ2dwbG90KGRmX2xvbmcsIGFlcyh4ID0gc2FzZGF0ZSwgeSA9IHZhbHVlLCBjb2xvciA9IHZhcmlhYmxlKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsNCiAgZmFjZXRfd3JhcCh+dmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlX3kiLCBuY29sID0gMikgKw0KICBsYWJzKHRpdGxlID0gIlNlcmllcyBoaXN0b3JpY2FzIGRlbCB5X2dhcCIsDQogICAgICAgeCA9ICJGZWNoYSIsDQogICAgICAgeSA9ICJWYWxvciIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQojIyBJbmZsYXRpb24gR2FwDQpMYSBicmVjaGEgZGUgaW5mbGFjacOzbiBtaWRlIGVsIGRlc3bDrW8gZW50cmUgbGEgaW5mbGFjacOzbiBvYnNlcnZhZGEgeSBsYSBtZXRhIGltcGzDrWNpdGEgZGUgbGEgUmVzZXJ2YSBGZWRlcmFsLiBQYXJhIGVzdGUgdHJhYmFqbyBzZSB1dGlsaXphIHVuIG9iamV0aXZvIGFudWFsIGRlbCAyJSwgcXVlIGVuIGZyZWN1ZW5jaWEgdHJpbWVzdHJhbCBlcXVpdmFsZSBhcHJveGltYWRhbWVudGUgYSAwLDUlLiBMYSB2YXJpYWJsZSBwaV9nYXAgc2UgZGVmaW5lIGVudG9uY2VzIGNvbW8gbGEgZGlmZXJlbmNpYSBlbnRyZSBsYSBpbmZsYWNpw7NuIHRyaW1lc3RyYWwgZXN0aW1hZGEgYSBwYXJ0aXIgZGVsIMOtbmRpY2UgUENFIHkgZXN0YSBtZXRhLg0KDQpgYGB7ciBpbmZfZ2FwfQ0KIyBJbmZsYWNpb24gVHJpbWVzdHJhbCBvYmpldGl2bw0KcGlfc3Rhcl9xIDwtIDAuNQ0KDQojIEV4dHJhZW1vcyBkZWwgaW5kaWNlIGRlIHByZWNpb3MgbGEgaW5mbGFjaW9uIHRyaW1lc3RyYWwgY29uIGxhIGFwcm94aW1hY2lvbiBsb2ctZGlmZg0KZGYgPC0gZGYgJT4lDQogIGFycmFuZ2Uoc2FzZGF0ZSkgJT4lDQogIG11dGF0ZSgNCiAgICBpbmZsX3EgPSAxMDAgKiAobG9nKFBDRUNUUEkpIC0gZHBseXI6OmxhZyhsb2coUENFQ1RQSSksIDEpKSwgIyBpbmZsYWNpw7NuIHRyaW1lc3RyYWwgZW4gJSAoYXByb3ggbG9nLWRpZmYpDQogICAgcGlfZ2FwID0gaW5mbF9xIC0gcGlfc3Rhcl9xDQogICkgJT4lDQogIGRyb3BfbmEocGlfZ2FwKQ0KDQojIFNlbGVjY2lvbmFtb3MgbGEgdmFyaWFibGUgeSBwYXNhbW9zIGEgZm9ybWF0byBsYXJnbw0KZGZfbG9uZyA8LSBkZiAlPiUNCiAgZHBseXI6OnNlbGVjdChzYXNkYXRlLHBpX2dhcCkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gLXNhc2RhdGUsIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbHVlIikNCg0KZGZfbG9uZyA8LSBkZl9sb25nICU+JQ0KICBmaWx0ZXIoc2FzZGF0ZSA+IGFzLkRhdGUoIjE5ODAtMDEtMDEiKSAmIHNhc2RhdGUgPCBhcy5EYXRlKCIyMDA3LTAxLTAxIikgKQ0KDQojIEdyw6FmaWNvIGhpc3TDs3JpY28NCmdncGxvdChkZl9sb25nLCBhZXMoeCA9IHNhc2RhdGUsIHkgPSB2YWx1ZSwgY29sb3IgPSB2YXJpYWJsZSkpICsNCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArDQogIGZhY2V0X3dyYXAofnZhcmlhYmxlLCBzY2FsZXMgPSAiZnJlZV95IiwgbmNvbCA9IDIpICsNCiAgbGFicyh0aXRsZSA9ICJTZXJpZXMgaGlzdG9yaWNhcyBkZWwgZGVzdmlvIGRlIGxhIGluZmxhY2lvbiByZXNwZWN0byBhIGxhIG9iamV0aXZhIiwNCiAgICAgICB4ID0gIkZlY2hhIiwNCiAgICAgICB5ID0gIlZhbG9yIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCiMjIEluZXJjaWEgZGUgbGEgdGFzYSBkZSBpbnRlcsOpcw0KUGFyYSBjYXB0dXJhciBlbCBjb21wb3J0YW1pZW50byBncmFkdWFsIGRlIGxhIHBvbMOtdGljYSBtb25ldGFyaWEsIHNlIGluY29ycG9yYSBsYSB0YXNhIGRlIGZvbmRvcyBmZWRlcmFsZXMgcmV6YWdhZGEgdW4gcGVyw61vZG8gKGlfbGFnMSkuIEVzdGEgdmFyaWFibGUgcmVmbGVqYSBsYSBpbmVyY2lhIHTDrXBpY2EgY29uIGxhIHF1ZSBsYSBSZXNlcnZhIEZlZGVyYWwgYWp1c3RhIGxhIHRhc2EgZGUgaW50ZXLDqXMsIGRhZG8gcXVlIGxvcyBjYW1iaW9zIHN1ZWxlbiByZWFsaXphcnNlIGRlIG1hbmVyYSBwcm9ncmVzaXZhIHkgbm8gYWJydXB0YSBkZSB1biB0cmltZXN0cmUgYSBvdHJvLiANCmBgYHtyIGluZXJjaWF9DQojIENvbnRydWltb3MgbGFzIHZhcmlhYmxlcyBsYWdzIGRlIGludGVyZXMgeSBjYW1iaW8gZW4gbGEgdGFzYSBkZSBpbnRlcmVzDQpkZiA8LSBkZiAlPiUNCiAgYXJyYW5nZShzYXNkYXRlKSAlPiUNCiAgbXV0YXRlKA0KICAgIGlfbGFnMSAgID0gZHBseXI6OmxhZyhGRURGVU5EUywgMSksICMgdGFzYSByZXphZ2FkYSAxDQogICAgZGVsdGFfaSAgPSBGRURGVU5EUyAtIGlfbGFnMSAjIGNhbWJpbyBlbiBsYSB0YXNhDQogICkgJT4lDQogIGRyb3BfbmEoaV9sYWcxLCBkZWx0YV9pKQ0KDQpkZl9sb25nIDwtIGRmICU+JQ0KICBkcGx5cjo6c2VsZWN0KHNhc2RhdGUsIGRlbHRhX2ksIEZFREZVTkRTKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtc2FzZGF0ZSwgbmFtZXNfdG8gPSAidmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUNCiAgZmlsdGVyKHNhc2RhdGUgPiBhcy5EYXRlKCIxOTgwLTAxLTAxIikgJiBzYXNkYXRlIDwgYXMuRGF0ZSgiMjAwNy0wMS0wMSIpKSAlPiUNCiAgbXV0YXRlKA0KICAgIHZhcmlhYmxlID0gcmVjb2RlKHZhcmlhYmxlLA0KICAgICAgICAgICAgICAgICAgICAgIEZFREZVTkRTID0gIkZFREZVTkRTIiwNCiAgICAgICAgICAgICAgICAgICAgICBkZWx0YV9pICA9ICJEZWx0YV9pIiksDQogICAgdmFyaWFibGUgPSBmYWN0b3IodmFyaWFibGUsIGxldmVscyA9IGMoIkZFREZVTkRTIiwgIkRlbHRhX2kiKSkNCiAgKQ0KDQpnZ3Bsb3QoZGZfbG9uZywgYWVzKHggPSBzYXNkYXRlLCB5ID0gdmFsdWUsIGNvbG9yID0gdmFyaWFibGUpKSArDQogIGdlb21fbGluZShzaXplID0gMSkgKw0KICBmYWNldF93cmFwKH52YXJpYWJsZSwgc2NhbGVzID0gImZyZWVfeSIsIG5yb3cgPSAyKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiU2VyaWVzIGhpc3TDs3JpY2FzIGRlIGxhIHRhc2EgZGUgaW50ZXLDqXMgeSBzdSBjYW1iaW8gcmVzcGVjdG8gYWwgdHJpbWVzdHJlIGFudGVyaW9yIiwNCiAgICB4ID0gIkZlY2hhIiwNCiAgICB5ID0gIlZhbG9yIiwNCiAgICBjb2xvciA9ICJWYXJpYWJsZXMiDQogICkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwoDQogICAgdmFsdWVzID0gYygiRkVERlVORFMiID0gIiMxRjc3QjQiLCAiRGVsdGFfaSIgPSAiI0ZGN0YwRSIpLA0KICAgIGxhYmVscyA9IGMoIkZFREZVTkRTIiA9ICJGRURGVU5EUyIsICJEZWx0YV9pIiA9ICJEZWx0YV9pIikNCiAgKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcihhY2N1cmFjeSA9IDAuMSkpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCg0KYGBgDQoNCiMjIEFuw6FsaXNpcyBFc3RhZGlzdGljb3MgZGUgbGFzIHZhcmlhYmxlcw0KRW4gcHJpbWVyIGx1Z2FyLCBhbmFsaXphcmVtb3MgbGFzIHZhcmlhYmxlcyBhIHRyYXbDqXMgZGUgc3VzIG1lZGlkYXMgZGUgdGVuZGVuY2lhIHBhcmEgZWwgcGVyaW9kbyBlbiBjdWVzdGnDs24uDQpgYGB7ciBhbmFsaXNpcyBlc3RhZGlzdGljb30NCg0KZGZfZGVzYyA8LSBkZiAlPiUgZmlsdGVyKHNhc2RhdGUgPiBhcy5EYXRlKCIxOTgwLTAxLTAxIikgJiBzYXNkYXRlIDwgYXMuRGF0ZSgiMjAwNy0wMS0wMSIpICkNCg0KZGZfZGVzYyA8LSBkZl9kZXNjICU+JSBkcGx5cjo6c2VsZWN0KEdEUEMxLCBHRFBQT1QsIEZFREZVTkRTLCB5X2dhcCwgaW5mbF9xLCBwaV9nYXAsIGRlbHRhX2kpDQoNCnN1bW1hcnlfc3RhdHMgPC0gZGZfZGVzYyAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGFjcm9zcygNCiAgICAgIGV2ZXJ5dGhpbmcoKSwNCiAgICAgIGxpc3QoDQogICAgICAgIG1pbiAgPSB+bWluKC4gLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICBtYXggID0gfm1heCguICwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgbWVhbiA9IH5tZWFuKC4gLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICBzZCAgID0gfnNkKC4gLCBuYS5ybSA9IFRSVUUpDQogICAgICApLA0KICAgICAgLm5hbWVzID0gInsuY29sfV97LmZufSINCiAgICApDQogICkgJT4lDQogIHBpdm90X2xvbmdlcigNCiAgICBldmVyeXRoaW5nKCksDQogICAgbmFtZXNfdG8gPSBjKCJ2YXJpYWJsZSIsICJzdGF0IiksDQogICAgbmFtZXNfcGF0dGVybiA9ICIoLiopXyguKikiDQogICkgJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzdGF0LCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSAlPiUNCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfnJvdW5kKC4gLCAyKSkpDQoNCnN1bW1hcnlfc3RhdHMNCg0KDQpgYGANCkVuIHNlZ3VuZG8gbHVnYXIsIGFuYWxpemFyZW1vcyBsYSBldm9sdWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgZGVzZGUgZWwgZW5mb3F1ZSBoaXN0w7NyaWNvIGRlIGxhcyBzZXJpZXMgZGUgdGllbXBvLiBDb24gZWwgZmluIGRlIHJlcHJlc2VudGFybGFzIGRlIG1hbmVyYSBjb25qdW50YSBlbiB1biBtaXNtbyBncsOhZmljbywgcmVjdXJyaW1vcyBhbCBwcm9jZXNvIGRlIGVzdGFuZGFyaXphY2nDs24uIEVzdGUgcHJvY2VkaW1pZW50byB0cmFuc2Zvcm1hIGNhZGEgb2JzZXJ2YWNpw7NuIGVuIHVuIHrigJFzY29yZSwgZXMgZGVjaXIsIGVuIGxhIGNhbnRpZGFkIGRlIGRlc3ZpYWNpb25lcyBlc3TDoW5kYXIgcXVlIGRpY2hvIHZhbG9yIHNlIGVuY3VlbnRyYSBwb3IgZW5jaW1hIG8gcG9yIGRlYmFqbyBkZSBsYSBtZWRpYSBkZSBsYSB2YXJpYWJsZS4gRGUgZXN0YSBmb3JtYSwgbGFzIHRyZXMgc2VyaWVzIHF1ZWRhbiBleHByZXNhZGFzIGVuIHVuYSBlc2NhbGEgY29tw7puLCBsbyBxdWUgZmFjaWxpdGEgbGEgY29tcGFyYWNpw7NuIGRlIHN1cyBkaW7DoW1pY2FzIGEgbG8gbGFyZ28gZGVsIHRpZW1wby4NCg0KYGBge3IgZ3JhZmljb3MgaGlzdG9yaWNvc30NCg0KIyBTZWxlY2Npb25hbW9zIGxhcyB2YXJpYWJsZXMgeSBwYXNhbW9zIGEgZm9ybWF0byBsYXJnbw0KDQpkZl9ub3JtIDwtIGRmICU+JQ0KICBkcGx5cjo6c2VsZWN0KHNhc2RhdGUsIEZFREZVTkRTLCBwaV9nYXAsIHlfZ2FwKSAlPiUNCiAgbXV0YXRlKA0KICAgIEZFREZVTkRTX3ogPSBzY2FsZShGRURGVU5EUyksDQogICAgcGlfZ2FwX3ogICA9IHNjYWxlKHBpX2dhcCksDQogICAgeV9nYXBfeiAgICA9IHNjYWxlKHlfZ2FwKQ0KICApICU+JQ0KICBkcGx5cjo6c2VsZWN0KHNhc2RhdGUsIEZFREZVTkRTX3osIHBpX2dhcF96LCB5X2dhcF96KSAlPiUNCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtc2FzZGF0ZSwNCiAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsDQogICAgdmFsdWVzX3RvID0gInZhbHVlIg0KICApICAlPiUgDQogICAgZmlsdGVyKHNhc2RhdGUgPiBhcy5EYXRlKCIxOTgwLTAxLTAxIikgJiBzYXNkYXRlIDwgYXMuRGF0ZSgiMjAwNy0wMS0wMSIpICkNCg0KcCA8LSBnZ3Bsb3QoZGZfbm9ybSwgYWVzKA0KICAgIHggPSBzYXNkYXRlLA0KICAgIHkgPSB2YWx1ZSwNCiAgICBjb2xvciA9IHZhcmlhYmxlLA0KICAgIGdyb3VwID0gdmFyaWFibGUsDQogICAgdGV4dCA9IHBhc3RlMCgNCiAgICAgICJGZWNoYTogIiwgZm9ybWF0KHNhc2RhdGUsICIlWS0lbSIpLCAiPGJyPiIsDQogICAgICAiVmFyaWFibGU6ICIsIGRwbHlyOjpyZWNvZGUodmFyaWFibGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRkVERlVORFNfeiA9ICJUYXNhIEZlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGlfZ2FwX3ogICA9ICJJbmZsYXRpb24gZ2FwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2dhcF96ICAgID0gIk91dHB1dCBnYXAiKSwgIjxicj4iLA0KICAgICAgIlZhbG9yOiAiLCBzcHJpbnRmKCIlLjJmIiwgdmFsdWUpDQogICAgKQ0KICApKSArDQogIGdlb21fbGluZShzaXplID0gMS4yKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRXZvbHVjacOzbiBjb21wYXJhZGE6IHRhc2EgZGUgbGEgRmVkIHkgYnJlY2hhcyAobm9ybWFsaXphZGFzKSIsDQogICAgeCA9ICJGZWNoYSIsDQogICAgeSA9ICJWYWxvcmVzIG5vcm1hbGl6YWRvcyAoei1zY29yZSkiLA0KICAgIGNvbG9yID0gTlVMTA0KICApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKA0KICAgIHZhbHVlcyA9IGMoDQogICAgICBGRURGVU5EU196ID0gIiMxRjc3QjQiLA0KICAgICAgcGlfZ2FwX3ogICA9ICIjQUVDN0U4IiwNCiAgICAgIHlfZ2FwX3ogICAgPSAiIzk4REY4QSINCiAgICApLA0KICAgIGxhYmVscyA9IGMoIlRhc2EgRmVkIiwgIkluZmxhdGlvbiBnYXAiLCAiT3V0cHV0IGdhcCIpDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMiwgaGp1c3QgPSAwLjUpLA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyYXkzMCIpDQogICkNCg0KZ2dwbG90bHkocCwgdG9vbHRpcCA9ICJ0ZXh0IikgJT4lDQogIGxheW91dCgNCiAgICBsZWdlbmQgPSBsaXN0KA0KICAgICAgb3JpZW50YXRpb24gPSAiaCIsDQogICAgICB4ID0gMC4yLA0KICAgICAgeSA9IDAuMQ0KICAgICkNCiAgKQ0KDQoNCmBgYA0KDQojIFJlZ3Jlc2lvbmVzDQoNCiMjIE9MUw0KU2UgZGV0ZXJtaW5hIHVuYSB2ZW50YW5hIHRlbXBvcmFsIHkgc2UgcHJvY2VkZSBjb24gbGEgcmVncmVzacOzbiB0cmFkaWNpb25hbC4NCmBgYHtyIHJlZ30NCmRmX3JlZ19zdWIgPC0gZGYgJT4lDQogIGZpbHRlcihzYXNkYXRlID4gYXMuRGF0ZSgiMTk4MC0wMS0wMSIpICYgc2FzZGF0ZSA8IGFzLkRhdGUoIjIwMDctMDEtMDEiKSApDQpgYGANCmBgYHtyIHJlZ19yZXN1bHR9DQp0YXlsb3Jfb2xzIDwtIGxtKA0KICBGRURGVU5EUyB+IGlfbGFnMSArIHBpX2dhcCArIHlfZ2FwLA0KICBkYXRhID0gZGZfcmVnX3N1Yg0KKQ0KDQpzdW1tYXJ5KHRheWxvcl9vbHMpDQpgYGANCkxhIGVzdGltYWNpw7NuIE9MUyBkZSBsYSBSZWdsYSBkZSBUYXlsb3IgYXJyb2phIHVuIGNvZWZpY2llbnRlIGRlIGluZXJjaWEgZWxldmFkbyBwYXJhIGxhIHRhc2EgZGUgaW50ZXLDqXMgKGlfbGFnMSDiiYggMCw4OSksIGxvIHF1ZSBpbmRpY2EgcXVlIGxhIFJlc2VydmEgRmVkZXJhbCBhanVzdGEgbGEgcG9sw610aWNhIG1vbmV0YXJpYSBkZSBtYW5lcmEgZ3JhZHVhbC4gVGFudG8gbGEgYnJlY2hhIGRlIGluZmxhY2nDs24gKHBpX2dhcCDiiYggMCw4OSkgY29tbyBlbCBvdXRwdXQgZ2FwICh5X2dhcCDiiYggMCwxNykgcHJlc2VudGFuIHNpZ25vcyBwb3NpdGl2b3MgeSBzb24gZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2b3MsIGVuIGzDrW5lYSBjb24gbGEgaWRlYSBkZSBxdWUgbGEgdGFzYSBkZSBmb25kb3MgZmVkZXJhbGVzIGF1bWVudGEgY3VhbmRvIGxhIGluZmxhY2nDs24gc2UgdWJpY2EgcG9yIGVuY2ltYSBkZSBsYSBtZXRhIHkgY3VhbmRvIGxhIGFjdGl2aWRhZCBzZSBzaXTDumEgcG9yIGVuY2ltYSBkZSBzdSBuaXZlbCBwb3RlbmNpYWwuIEVsIG1vZGVsbyBleGhpYmUgdW4gbXV5IGJ1ZW4gYWp1c3RlIChSwrIg4omIIDAsOTQpLCBwb3IgbG8gcXVlIGxhIGVzcGVjaWZpY2FjacOzbiBlc3RpbWFkYSBjYXB0dXJhIHJhem9uYWJsZW1lbnRlIGJpZW4gZWwgY29tcG9ydGFtaWVudG8gaGlzdMOzcmljbyBkZSBsYSBwb2zDrXRpY2EgbW9uZXRhcmlhIGVuIGVsIHBlcsOtb2RvIGNvbnNpZGVyYWRvLg0KDQojIyBSZWdyZXNpw7NuIEJheWVzaWFuYSAjMSAtIFByaW9ycyBEw6liaWxlcw0KQWRlbcOhcyBkZSBsYSBlc3RpbWFjacOzbiBtZWRpYW50ZSBNw61uaW1vcyBDdWFkcmFkb3MgT3JkaW5hcmlvcywgc2UgaW1wbGVtZW50w7MgdW5hIHZlcnNpw7NuIGJheWVzaWFuYSBkZSBsYSBSZWdsYSBkZSBUYXlsb3IuIEVzdGUgZW5mb3F1ZSBwZXJtaXRlIGNvbWJpbmFyIGxhIGluZm9ybWFjacOzbiBwcmVzZW50ZSBlbiBsb3MgZGF0b3MgY29uIGNvbm9jaW1pZW50byBwcmV2aW8gc29icmUgZWwgY29tcG9ydGFtaWVudG8gdMOtcGljbyBkZSBsYSBwb2zDrXRpY2EgbW9uZXRhcmlhLiBQYXJhIGVzdGEgcHJpbWVyYSBlc3BlY2lmaWNhY2nDs24gc2UgdXRpbGl6YXJvbiBwcmlvcnMgaW5mb3JtYXRpdmFzIGJhc2FkYXMgZW4gZXN0aW1hY2lvbmVzIHJlcG9ydGFkYXMgZW4gZXN0dWRpb3MgZGVsIEJJUywgcXVlIHJlZmxlamFuIHZhbG9yZXMgdMOtcGljb3MgcGFyYSBsYSBpbmVyY2lhIG1vbmV0YXJpYSB5IGxhcyByZXNwdWVzdGFzIGEgaW5mbGFjacOzbiB5IGFjdGl2aWRhZCBlY29uw7NtaWNhLg0KDQpgYGB7ciBiYXllc192MSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnByaW9yc192MSA8LSBjKA0KICBwcmlvcihub3JtYWwoMCwgICAgNSksIGNsYXNzID0gIkludGVyY2VwdCIpLA0KICBwcmlvcihub3JtYWwoMC43NCwgMiksIGNsYXNzID0gImIiLCBjb2VmID0gImlfbGFnMSIpLA0KICBwcmlvcihub3JtYWwoMi4xMSwgMiksIGNsYXNzID0gImIiLCBjb2VmID0gInBpX2dhcCIpLA0KICBwcmlvcihub3JtYWwoMC4yNiwgMiksIGNsYXNzID0gImIiLCBjb2VmID0gInlfZ2FwIiksDQogIA0KIyBQcmlvciBkw6liaWwgcGFyYSBzaWdtYSAoZGVzdsOtbyBlc3TDoW5kYXIgcmVzaWR1YWwpDQogIHByaW9yKHN0dWRlbnRfdCgzLCAwLCAxMCksIGNsYXNzID0gInNpZ21hIikNCikNCg0Kc2V0LnNlZWQoNDIpDQoNCnRheWxvcl9iYXllc192MV9icm1zIDwtIGJybSgNCiAgRkVERlVORFMgfiBpX2xhZzEgKyBwaV9nYXAgKyB5X2dhcCwNCiAgZGF0YSAgID0gZGZfcmVnX3N1YiwNCiAgZmFtaWx5ID0gZ2F1c3NpYW4oKSwNCiAgcHJpb3IgID0gcHJpb3JzX3YxLA0KICBjaGFpbnMgPSA0LA0KICBpdGVyICAgPSAxNTAwMCwgICAjIHRvdGFsIGRyYXdzIHBvciBjYWRlbmENCiAgd2FybXVwID0gNTAwMCwgICAgIyBidXJuLWluDQogIGNvcmVzICA9IDQsDQogIHNlZWQgICA9IDQyLA0KICBzYW1wbGVfcHJpb3IgPSAieWVzIg0KKQ0KYGBgDQpgYGB7ciBiYXllc192MV9yZXN1bHR9DQpzdW1tYXJ5KHRheWxvcl9iYXllc192MV9icm1zKQ0KYGBgDQpMb3MgcmVzdWx0YWRvcyBiYXllc2lhbm9zIGNvbiBwcmlvcnMgZMOpYmlsZXMgc29uIG11eSBzaW1pbGFyZXMgYSBsb3MgZGUgT0xTOiBsb3MgY29lZmljaWVudGVzIGRlIGluZXJjaWEsIGluZmxhY2nDs24geSBvdXRwdXQgZ2FwIG1hbnRpZW5lbiBtYWduaXR1ZGVzIGNhc2kgaWTDqW50aWNhcyB5IGNvbnRpbsO6YW4gc2llbmRvIGNsYXJhbWVudGUgc2lnbmlmaWNhdGl2b3MuIExvcyBpbnRlcnZhbG9zIGFsIDk1JSByZWZsZWphbiBsYSBtaXNtYSBpbmZvcm1hY2nDs24gcXVlIGxvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSBjbMOhc2ljb3MsIGluZGljYW5kbyBxdWUgbGFzIHByaW9ycyBubyBhbHRlcmFuIHN1c3RhbmNpYWxtZW50ZSBsYSBlc3RpbWFjacOzbi4gRW4gc8OtbnRlc2lzLCBlbCBtb2RlbG8gYmF5ZXNpYW5vIHJlcHJvZHVjZSBkZSBtYW5lcmEgY29uc2lzdGVudGUgbGEgZXN0cnVjdHVyYSBvYnRlbmlkYSBwb3IgT0xTLg0KDQojIyBSZWdyZXNpw7NuIEJheWVzaWFuYSAjMiAtIFByaW9ycyBGdWVydGVzDQpFbiBlc3RhIHNlZ3VuZGEgZXNwZWNpZmljYWNpw7NuIHNlIG1hbnRpZW5lIGxhIG1pc21hIGVzdHJ1Y3R1cmEgZGVsIG1vZGVsbywgcGVybyBzZSByZWVtcGxhemFuIGxhcyBwcmlvcnMgZMOpYmlsZXMgcG9yIHByaW9ycyBtdWNobyBtw6FzIGNvbmNlbnRyYWRhcywgYmFzYWRhcyBlbiBlc3RpbWFjaW9uZXMgZGVsIEJJUy4gRXN0byBwZXJtaXRlIGV2YWx1YXIgY3XDoW50byBpbmZsdXllbiBsYXMgY3JlZW5jaWFzIHByZXZpYXMgZW4gbG9zIGNvZWZpY2llbnRlcyBkZSBsYSBSZWdsYSBkZSBUYXlsb3IsIGZvcnphbmRvIGFsIG1vZGVsbyBhIGNvbWVuemFyIGRlc2RlIHZhbG9yZXMgbXV5IGVzcGVjw61maWNvcyBwYXJhIGxhIGluZXJjaWEgbW9uZXRhcmlhLCBsYSByZXNwdWVzdGEgYSBsYSBpbmZsYWNpw7NuIHkgbGEgcmVzcHVlc3RhIGFsIGNpY2xvLg0KDQpgYGB7ciBiYXllc192MiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnByaW9yc192MiA8LSBjKA0KICBwcmlvcihub3JtYWwoMCwgICAgNS4wKSwgY2xhc3MgPSAiSW50ZXJjZXB0IiksDQogIHByaW9yKG5vcm1hbCgwLjc0LCAwLjEwKSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAiaV9sYWcxIiksDQogIHByaW9yKG5vcm1hbCgyLjExLCAwLjEwKSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAicGlfZ2FwIiksDQogIHByaW9yKG5vcm1hbCgwLjI2LCAwLjA1KSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAieV9nYXAiKSwNCiAgDQojIFByaW9yIGTDqWJpbCBwYXJhIHNpZ21hIChhbsOhbG9nbyBhIGludi1nYW1tYSBtdXkgcGxhbmEgZW4gc2lnbWFeMikNCiAgcHJpb3Ioc3R1ZGVudF90KDMsIDAsIDEwKSwgY2xhc3MgPSAic2lnbWEiKQ0KKQ0KDQpzZXQuc2VlZCg0MikNCg0KdGF5bG9yX2JheWVzX3YyX2JybXMgPC0gYnJtKA0KICBGRURGVU5EUyB+IGlfbGFnMSArIHBpX2dhcCArIHlfZ2FwLA0KICBkYXRhICAgPSBkZl9yZWdfc3ViLA0KICBmYW1pbHkgPSBnYXVzc2lhbigpLA0KICBwcmlvciAgPSBwcmlvcnNfdjIsDQogIA0KICBjaGFpbnMgPSA0LA0KICBpdGVyICAgPSAxNTAwMCwNCiAgd2FybXVwID0gNTAwMCwNCiAgY29yZXMgID0gNCwNCiAgc2VlZCAgID0gNDIsDQogIHNhbXBsZV9wcmlvciA9ICJ5ZXMiDQopDQpgYGANCmBgYHtyIGJheWVzX3YyX3Jlc3VsdH0NCnN1bW1hcnkodGF5bG9yX2JheWVzX3YyX2JybXMpDQpgYGANCkxvcyByZXN1bHRhZG9zIGNvbiBwcmlvcnMgZnVlcnRlcyBtdWVzdHJhbiBjb2VmaWNpZW50ZXMgY2xhcmFtZW50ZSBpbmZsdWVuY2lhZG9zIHBvciBsYSBpbmZvcm1hY2nDs24gcHJldmlhOiBsYSByZXNwdWVzdGEgYSBsYSBpbmZsYWNpw7NuIGF1bWVudGEgZGUgbWFuZXJhIG1hcmNhZGEgKOKJiCAxLjk1KSwgbWllbnRyYXMgcXVlIGxhIGluZXJjaWEgbW9uZXRhcmlhIHNlIHJlZHVjZSAo4omIIDAuNzkpLCBtb3Zpw6luZG9zZSBhbWJvcyBlbiBkaXJlY2Npw7NuIGEgbG9zIHZhbG9yZXMgZmlqYWRvcyBlbiBsYXMgcHJpb3JzLiBFbCBvdXRwdXQgZ2FwIHRhbWJpw6luIHByZXNlbnRhIHVuIGNvZWZpY2llbnRlIG1heW9yICjiiYggMC4yMikuIFRvZG9zIGxvcyBwYXLDoW1ldHJvcyByZXN1bHRhbiBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZvcyByZWZsZWphbmRvIGxhIG1heW9yIHByZWNpc2nDs24gaW1wdWVzdGEgcG9yIGxhcyBwcmlvcnMuIEVuIGNvbmp1bnRvLCBlc3RhIHZlcnNpw7NuIGRlbCBtb2RlbG8gaWx1c3RyYSBjw7NtbyBwcmlvcnMgbcOhcyBjb25jZW50cmFkYXMgcHVlZGVuIG1vZGlmaWNhciBzdXN0YW5jaWFsbWVudGUgbGFzIGVzdGltYWNpb25lcy4NCg0KIyBBbsOhbGlzaXMgR3LDoWZpY28NCg0KIyMgMSkgRm9yZXN0IHBsb3QNCkVsIGdyw6FmaWNvIGNvbXBhcmEgbG9zIGNvZWZpY2llbnRlcyBlc3RpbWFkb3MgcG9yIE9MUyBjb24gbGFzIGRpc3RyaWJ1Y2lvbmVzIHBvc3RlcmlvcmVzIG9idGVuaWRhcyBiYWpvIGxvcyBtb2RlbG9zIGJheWVzaWFub3MgY29uIHByaW9ycyBkw6liaWxlcyB5IGZ1ZXJ0ZXMuIFNlIG9ic2VydmEgcXVlLCBtaWVudHJhcyBsYSB2ZXJzacOzbiBjb24gcHJpb3JzIGTDqWJpbGVzIHJlcHJvZHVjZSBjYXNpIGV4YWN0YW1lbnRlIGxvcyB2YWxvcmVzIGRlIE9MUywgbGFzIHByaW9ycyBmdWVydGVzIGRlc3BsYXphbiBsYXMgZGlzdHJpYnVjaW9uZXMgaGFjaWEgbG9zIHZhbG9yZXMgaW1wdWVzdG9zIHBvciBsYSBpbmZvcm1hY2nDs24gcHJldmlhLCBlc3BlY2lhbG1lbnRlIGVuIGxhIHJlc3B1ZXN0YSBhIGxhIGluZmxhY2nDs24uIEVzdG8gcGVybWl0ZSB2aXN1YWxpemFyIGRlIG1hbmVyYSBkaXJlY3RhIGPDs21vIGVsIHBlc28gZGUgbGFzIHByaW9ycyBhZmVjdGEgbGEgZXN0aW1hY2nDs24gZGUgY2FkYSBwYXLDoW1ldHJvLg0KYGBge3IgZm9yZXN0LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBpKSBDb2VmaWNpZW50ZXMgT0xTDQpvbHNfdGlkeSA8LSBicm9vbTo6dGlkeSh0YXlsb3Jfb2xzLCBjb25mLmludCA9IFRSVUUpICU+JQ0KICBmaWx0ZXIodGVybSAhPSAiKEludGVyY2VwdCkiKSAlPiUNCiAgbXV0YXRlKG1vZGVsID0gIk9MUyIpDQoNCiMgaWkpIENvZWZpY2llbnRlcyBCYXllczogZHJhd3MgZGUgYnJtcw0KYjFfZHJhd3MgPC0gdGF5bG9yX2JheWVzX3YxX2JybXMgJT4lDQogIHNwcmVhZF9kcmF3cyhiX2lfbGFnMSwgYl9waV9nYXAsIGJfeV9nYXApICU+JQ0KICBkcGx5cjo6c2VsZWN0KGJfaV9sYWcxLCBiX3BpX2dhcCwgYl95X2dhcCkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidGVybSIsDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUNCiAgbXV0YXRlKG1vZGVsID0gIk1vZGVsbyBjb24gcHJpb3JzIGTDqWJpbGVzIikNCg0KYjJfZHJhd3MgPC0gdGF5bG9yX2JheWVzX3YyX2JybXMgJT4lDQogIHNwcmVhZF9kcmF3cyhiX2lfbGFnMSwgYl9waV9nYXAsIGJfeV9nYXApICU+JQ0KICBkcGx5cjo6c2VsZWN0KGJfaV9sYWcxLCBiX3BpX2dhcCwgYl95X2dhcCkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidGVybSIsDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUNCiAgbXV0YXRlKG1vZGVsID0gIk1vZGVsbyBjb24gcHJpb3JzIGZ1ZXJ0ZXMiKQ0KDQpiYXllc19kcmF3cyA8LSBiaW5kX3Jvd3MoYjFfZHJhd3MsIGIyX2RyYXdzKSAlPiUNCiAgbXV0YXRlKHRlcm0gPSByZWNvZGUodGVybSwNCiAgICAgICAgICAgICAgICAgICAgICAgYl9pX2xhZzEgPSAiaV9sYWcxIChyaG8pIiwNCiAgICAgICAgICAgICAgICAgICAgICAgYl9waV9nYXAgPSAicGlfZ2FwIChwaGlfcGkpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgYl95X2dhcCAgPSAieV9nYXAgKHBoaV95KSIpKQ0KDQpvbHNfdGlkeSA8LSBvbHNfdGlkeSAlPiUNCiAgbXV0YXRlKHRlcm0gPSByZWNvZGUodGVybSwNCiAgICAgICAgICAgICAgICAgICAgICAgaV9sYWcxID0gImlfbGFnMSAocmhvKSIsDQogICAgICAgICAgICAgICAgICAgICAgIHBpX2dhcCA9ICJwaV9nYXAgKHBoaV9waSkiLA0KICAgICAgICAgICAgICAgICAgICAgICB5X2dhcCAgPSAieV9nYXAgKHBoaV95KSIpKQ0KDQojIGlpaSkgR3LDoWZpY28gY29tYmluYWRvDQpnZ3Bsb3QoYmF5ZXNfZHJhd3MsIGFlcyh4ID0gdmFsdWUsIHkgPSB0ZXJtLCBmaWxsID0gbW9kZWwpKSArDQogIHN0YXRfaGFsZmV5ZShhbHBoYSA9IDAuNywgcG9pbnRfaW50ZXJ2YWwgPSBtZWRpYW5fcWksIC53aWR0aCA9IDAuOTUpICsNCiAgZ2VvbV9wb2ludChkYXRhID0gb2xzX3RpZHksIGFlcyh4ID0gZXN0aW1hdGUsIHkgPSB0ZXJtKSwNCiAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCBzaGFwZSA9IDIxLCBzaXplID0gMi4yLCBmaWxsID0gIndoaXRlIikgKw0KICBnZW9tX2Vycm9yYmFyaChkYXRhID0gb2xzX3RpZHksDQogICAgICAgICAgICAgICAgIGFlcyh4bWluID0gY29uZi5sb3csIHhtYXggPSBjb25mLmhpZ2gsIHkgPSB0ZXJtKSwNCiAgICAgICAgICAgICAgICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgaGVpZ2h0ID0gMC4xNSkgKw0KICBsYWJzKHggPSAiVmFsb3IgZGVsIGNvZWZpY2llbnRlIiwgeSA9IE5VTEwsDQogICAgICAgdGl0bGUgPSAiT0xTIHZzIEJheWVzIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJEaXN0cmlidWNpb25lcyBwb3N0ZXJpb3JlcyB5IElDIE9MUyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyMgIDIpIFByaW9yIHZzIFBvc3RlcmlvciAocGFyYSAjMSB5ICMyKQ0KRWwgZ3LDoWZpY28gbXVlc3RyYSBjw7NtbyBzZSBjb21wYXJhbiBsYXMgZGlzdHJpYnVjaW9uZXMgcHJpb3IgeSBwb3N0ZXJpb3IgZW4gYW1ib3MgbW9kZWxvcy4gQ29uIHByaW9ycyBkw6liaWxlcywgbG9zIGRhdG9zIG1vZGlmaWNhbiBmdWVydGVtZW50ZSBsYSBkaXN0cmlidWNpw7NuIHBvc3Rlcmlvci4gQ29uIHByaW9ycyBmdWVydGVzLCBsYSBwb3N0ZXJpb3IgcGVybWFuZWNlIG11eSBjZXJjYSBkZSBsYSBwcmlvciwgaW5kaWNhbmRvIHF1ZSBsYSBpbmZvcm1hY2nDs24gcHJldmlhIHRpZW5lIG11Y2hvIG3DoXMgcGVzbyBlbiBsYSBlc3RpbWFjacOzbi4NCmBgYHtyIHByaW9yX3Bvc3QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9IA0KcGFycyA8LSBjKCJiX2lfbGFnMSIsICJiX3BpX2dhcCIsICJiX3lfZ2FwIikNCg0KbWFrZV9wcmlvcl9wb3N0X2xvbmcgPC0gZnVuY3Rpb24oZml0LCBsYWJlbCl7DQogIHByaW9yX2RmIDwtIHByaW9yX2RyYXdzKGZpdCkgJT4lDQogICAgYXNfZHJhd3NfZGYoKSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KGFsbF9vZihwYXJzKSkgJT4lDQogICAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAidGVybSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQ0KICAgIG11dGF0ZSh0eXBlID0gIlByaW9yIiwgbW9kZWwgPSBsYWJlbCkNCiAgDQogIHBvc3RfZGYgPC0gYXNfZHJhd3NfZGYoZml0KSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KGFsbF9vZihwYXJzKSkgJT4lDQogICAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAidGVybSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQ0KICAgIG11dGF0ZSh0eXBlID0gIlBvc3RlcmlvciIsIG1vZGVsID0gbGFiZWwpDQogIA0KICBiaW5kX3Jvd3MocHJpb3JfZGYsIHBvc3RfZGYpDQp9DQoNCmRmX3YxIDwtIG1ha2VfcHJpb3JfcG9zdF9sb25nKHRheWxvcl9iYXllc192MV9icm1zLCAiUHJpb3JzIGTDqWJpbGVzIikNCmRmX3YyIDwtIG1ha2VfcHJpb3JfcG9zdF9sb25nKHRheWxvcl9iYXllc192Ml9icm1zLCAiUHJpb3JzIGZ1ZXJ0ZXMiKQ0KDQpkZl9hbGwgPC0gYmluZF9yb3dzKGRmX3YxLCBkZl92MikgJT4lDQogIG11dGF0ZSgNCiAgICB0ZXJtID0gcmVjb2RlKHRlcm0sDQogICAgICAgICAgICAgICAgICBiX2lfbGFnMSA9ICJpX2xhZzEgKHJobykiLA0KICAgICAgICAgICAgICAgICAgYl9waV9nYXAgPSAicGlfZ2FwIChwaGlfcGkpIiwNCiAgICAgICAgICAgICAgICAgIGJfeV9nYXAgID0gInlfZ2FwIChwaGlfeSkiKSwNCiAgICB0ZXJtID0gZmFjdG9yKHRlcm0sIGxldmVscyA9IGMoImlfbGFnMSAocmhvKSIsICJwaV9nYXAgKHBoaV9waSkiLCAieV9nYXAgKHBoaV95KSIpKQ0KICApDQoNCmdncGxvdChkZl9hbGwsIGFlcyh4ID0gdmFsdWUsIHkgPSB0ZXJtLCBmaWxsID0gdHlwZSkpICsNCiAgc3RhdF9oYWxmZXllKGFscGhhID0gMC42LCBwb3NpdGlvbiA9ICJpZGVudGl0eSIsDQogICAgICAgICAgICAgICBwb2ludF9pbnRlcnZhbCA9IG1lZGlhbl9xaSwgLndpZHRoID0gMC45NSkgKw0KICBmYWNldF93cmFwKH5tb2RlbCkgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoLTEsIDQpKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUHJpb3IgdnMgUG9zdGVyaW9yIHBvciBtb2RlbG8iLA0KICAgIHN1YnRpdGxlID0gIkNvbXBhcmFjacOzbiB2aXN1YWwgcGFyYSBwcmlvcnMgZMOpYmlsZXMgeSBmdWVydGVzIiwNCiAgICB4ID0gIlZhbG9yIGRlbCBjb2VmaWNpZW50ZSIsIHkgPSBOVUxMDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyAzKSBDb21wYXJhY2nDs24gUHJlZGljdGl2YTogRml0dGVkIHZzIGFjdHVhbA0KRWwgZ3LDoWZpY28gY29tcGFyYSBsYSB0YXNhIG9ic2VydmFkYSBjb24gbGFzIHByZWRpY2Npb25lcyBvYnRlbmlkYXMgcG9yIE9MUyB5IHBvciBsb3MgbW9kZWxvcyBiYXllc2lhbm9zIGNvbiBwcmlvcnMgZMOpYmlsZXMgeSBmdWVydGVzLiBFbiBhbWJvcyBjYXNvcywgbGFzIHByZWRpY2Npb25lcyBiYXllc2lhbmFzIHNpZ3VlbiBtdXkgZGUgY2VyY2EgbGEgdHJheWVjdG9yaWEgaGlzdMOzcmljYSBkZSBsYSB0YXNhIGRlIGZvbmRvcyBmZWRlcmFsZXMsIHkgbGFzIGJhbmRhcyBjcmXDrWJsZXMgKDUwJSB5IDk1JSkgc29uIGVzdHJlY2hhcywgaW5kaWNhbmRvIGJ1ZW5hIHByZWNpc2nDs24gZGVsIG1vZGVsby4gTGFzIHByaW9ycyBmdWVydGVzIHByb2R1Y2VuIGludGVydmFsb3MgbGlnZXJhbWVudGUgbcOhcyBjb25jZW50cmFkb3MsIHJlZmxlamFuZG8gbWF5b3IgcGVzbyBkZSBsYSBpbmZvcm1hY2nDs24gcHJldmlhLg0KYGBge3IgcHJlZGljdCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0gDQpkZl9wbG90IDwtIGRmX3JlZ19zdWIgJT4lDQogIG11dGF0ZShmaXRfb2xzID0gcHJlZGljdCh0YXlsb3Jfb2xzLCBuZXdkYXRhID0gZGZfcmVnX3N1YikpDQoNCnByZWRfdjEgPC0gZGZfcmVnX3N1YiAlPiUNCiAgYWRkX2VwcmVkX2RyYXdzKHRheWxvcl9iYXllc192MV9icm1zLCBuZHJhd3MgPSAyMDAwKQ0KDQpwcmVkX3YyIDwtIGRmX3JlZ19zdWIgJT4lDQogIGFkZF9lcHJlZF9kcmF3cyh0YXlsb3JfYmF5ZXNfdjJfYnJtcywgbmRyYXdzID0gMjAwMCkNCg0Kc3VtbV9wcmVkIDwtIGZ1bmN0aW9uKHByZWRfZGYsIGxhYmVsKXsNCiAgcHJlZF9kZiAlPiUNCiAgICBncm91cF9ieShzYXNkYXRlKSAlPiUNCiAgICBtZWRpYW5fcWkoLmVwcmVkLCAud2lkdGggPSBjKDAuNSwgMC45NSkpICU+JQ0KICAgIG11dGF0ZShtb2RlbCA9IGxhYmVsKQ0KfQ0KDQpwMSA8LSBzdW1tX3ByZWQocHJlZF92MSwgIkJheWVzIHByaW9ycyBkw6liaWxlcyIpDQpwMiA8LSBzdW1tX3ByZWQocHJlZF92MiwgIkJheWVzIHByaW9ycyBmdWVydGVzIikNCg0KcHJlZF9iYW5kcyA8LSBiaW5kX3Jvd3MocDEsIHAyKQ0KDQpnZ3Bsb3QoZGZfcGxvdCwgYWVzKHggPSBzYXNkYXRlLCB5ID0gRkVERlVORFMpKSArDQogIGdlb21fbGluZShjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gZml0X29scyksIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgc3RhdF9saW5lcmliYm9uKGRhdGEgPSBwcmVkX2JhbmRzLA0KICAgICAgICAgICAgICAgICAgYWVzKHkgPSAuZXByZWQsIHltaW4gPSAubG93ZXIsIHltYXggPSAudXBwZXIsIGZpbGwgPSBtb2RlbCksDQogICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMjUpICsNCiAgZmFjZXRfd3JhcCh+bW9kZWwsIG5jb2wgPSAxKSArDQogIGxhYnModGl0bGUgPSAiUHJlZGljY2nDs246IE9MUyB2cyBCYXllcyIsDQogICAgICAgc3VidGl0bGUgPSAiQmFuZGFzIGNyZcOtYmxlcyA1MCUgeSA5NSUiLA0KICAgICAgIHkgPSAiRkVERlVORFMiLCB4ID0gTlVMTCkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyA0KSBEaXN0cmlidWNpb24gZGUgcmVhY2Npw7NuIGEgaW5mbGFjacOzbg0KTGEgZmlndXJhIG11ZXN0cmEgbGEgZGlzdHJpYnVjacOzbiBwb3N0ZXJpb3IgZGVsIHBhcsOhbWV0cm8gcXVlIG1pZGUgbGEgcmVzcHVlc3RhIGRlIGxhIHRhc2EgZGUgaW50ZXLDqXMgYSBsYSBpbmZsYWNpw7NuICjPlc+AKSBiYWpvIGFtYm9zIGNvbmp1bnRvcyBkZSBwcmlvcnMuIENvbiBwcmlvcnMgZMOpYmlsZXMsIGxhIGRpc3RyaWJ1Y2nDs24gZXMgbcOhcyBkaXNwZXJzYSB5IGNlbnRyYWRhIGFscmVkZWRvciBkZSB2YWxvcmVzIGNlcmNhbm9zIGEgMSwgbWllbnRyYXMgcXVlIGNvbiBwcmlvcnMgZnVlcnRlcyBzZSBjb25jZW50cmEgZW4gdG9ybm8gYWwgYmVuY2htYXJrIGRlIDIuMTEgcHJvcHVlc3RvIHBvciBlbCBCSVMgKGzDrW5lYSBwdW50ZWFkYSkuIEVzdG8gaWx1c3RyYSBjw7NtbyBsYSBpbmZvcm1hY2nDs24gcHJldmlhIGluZmx1eWUgZW4gbGEgbWFnbml0dWQgZXN0aW1hZGEgZGUgbGEgcmVhY2Npw7NuIGRlIHBvbMOtdGljYSBtb25ldGFyaWEuDQpgYGB7ciBpbmYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9IA0KYjFfcGhpX3BpIDwtIGFzX2RyYXdzX2RmKHRheWxvcl9iYXllc192MV9icm1zKSRiX3BpX2dhcA0KYjJfcGhpX3BpIDwtIGFzX2RyYXdzX2RmKHRheWxvcl9iYXllc192Ml9icm1zKSRiX3BpX2dhcA0KDQpkZl9waGkgPC0gdGliYmxlKA0KICB2YWx1ZSA9IGMoYjFfcGhpX3BpLCBiMl9waGlfcGkpLA0KICBtb2RlbCA9IHJlcChjKCJQcmlvcnMgZMOpYmlsZXMiLCJQcmlvcnMgZnVlcnRlcyIpLA0KICAgICAgICAgICAgICBjKGxlbmd0aChiMV9waGlfcGkpLCBsZW5ndGgoYjJfcGhpX3BpKSkpDQopDQoNCmdncGxvdChkZl9waGksIGFlcyh4ID0gdmFsdWUsIGZpbGwgPSBtb2RlbCkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArDQogIGdlb21fdmxpbmUoDQogICAgeGludGVyY2VwdCA9IDIuMTEsDQogICAgbGluZXR5cGUgPSAiZG90dGVkIiwNCiAgICBsaW5ld2lkdGggPSAxLjIsDQogICAgY29sb3IgPSAiYmxhY2siLA0KICAgIGFscGhhID0gMC45DQogICkgKw0KICBsYWJzKHRpdGxlID0gIlJlc3B1ZXN0YSBhIGluZmxhY2nDs24gKHBoaV9waSkiLA0KICAgICAgIHN1YnRpdGxlID0gIkzDrW5lYSBwdW50ZWFkYSA9IGJlbmNobWFyayBCSVMiLA0KICAgICAgIHggPSBleHByZXNzaW9uKHBoaVtwaV0pLCB5ID0gIkRlbnNpZGFkIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyA1KSBTdGFja2VkIFBQQw0KTG9zIGdyw6FmaWNvcyBQUEMgcGVybWl0ZW4gZXZhbHVhciBzaSBsb3MgbW9kZWxvcyBiYXllc2lhbm9zIHB1ZWRlbiByZXByb2R1Y2lyIGxhIGRpc3RyaWJ1Y2nDs24gb2JzZXJ2YWRhIGRlIGxhIHRhc2EgZGUgaW50ZXLDqXMuIFRhbnRvIGVsIG1vZGVsbyBjb24gcHJpb3JzIGTDqWJpbGVzIGNvbW8gZWwgZGUgcHJpb3JzIGZ1ZXJ0ZXMgZ2VuZXJhbiBkaXN0cmlidWNpb25lcyBzaW11bGFkYXMgY29oZXJlbnRlcyBjb24gbG9zIGRhdG9zIHJlYWxlcywgbG8gcXVlIGluZGljYSB1biBhanVzdGUgYWRlY3VhZG8uDQpgYGB7ciBwcGMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9IA0KcHBfY2hlY2sodGF5bG9yX2JheWVzX3YxX2JybXMsDQogICAgICAgICB0eXBlID0gImRlbnNfb3ZlcmxheSIsDQogICAgICAgICBuZHJhd3MgPSA1MCkgKw0KICBnZ3RpdGxlKCJQUEMgLSBQcmlvcnMgRMOpYmlsZXMiKSArDQogIGxhYnMoeCA9ICJGRURGVU5EUyIsIHkgPSAiRGVuc2lkYWQiKSArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4wNSkpKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpDQoNCnBwX2NoZWNrKHRheWxvcl9iYXllc192Ml9icm1zLA0KICAgICAgICAgdHlwZSA9ICJkZW5zX292ZXJsYXkiLA0KICAgICAgICAgbmRyYXdzID0gNTApICsNCiAgZ2d0aXRsZSgiUFBDIC0gUHJpb3JzIEZ1ZXJ0ZXMiKSArDQogIGxhYnMoeCA9ICJGRURGVU5EUyIsIHkgPSAiRGVuc2lkYWQiKSArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4wNSkpKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpDQpgYGANCg0KIyBCYXllc2lhbiBMYXNzbw0KDQpFbiBlc3RhIHNlY2Npw7NuIHNlIGV4dGllbmRlIGxhIGVzdGltYWNpw7NuIGRlIGxhIFJlZ2xhIGRlIFRheWxvciBpbmNvcnBvcmFuZG8gdW4gY29uanVudG8gZGUgdmFyaWFibGVzIG1hY3JvZWNvbsOzbWljYXMgYWRpY2lvbmFsZXMgKGNvbnRyb2xlcykuIFBhcmEgZXZpdGFyIHNvYnJlYWp1c3RlIHkgcGVybWl0aXIgcXVlIGVsIHByb3BpbyBtb2RlbG8gZGV0ZXJtaW5lIGN1w6FsZXMgZGUgZXN0b3MgY29udHJvbGVzIHNvbiByZWFsbWVudGUgcmVsZXZhbnRlcywgc2UgdXRpbGl6YSB1biBlbmZvcXVlIGJheWVzaWFubyBjb24gdW4gcHJpb3IgdGlwbyBMQVNTTyAoZGlzdHJpYnVjacOzbiBMYXBsYWNlKSwgcXVlIGluZHVjZSBzaHJpbmthZ2Ugc29icmUgdG9kb3MgbG9zIGNvZWZpY2llbnRlcyBhZGljaW9uYWxlcy4NCkxvcyBjb2VmaWNpZW50ZXMgY2VudHJhbGVzIGRlIGxhIFJlZ2xhIGRlIFRheWxvciDigJRpbmVyY2lhLCBicmVjaGEgZGUgaW5mbGFjacOzbiB5IG91dHB1dCBnYXDigJQgc2UgbWFudGllbmVuIGNvbiBwcmlvcnMgaW5mb3JtYXRpdm9zIGZ1ZXJ0ZXMgYXNlZ3VyYW5kbyBxdWUgTEFTU08gYWN0w7plIMO6bmljYW1lbnRlIHNvYnJlIGxvcyBjb250cm9sZXMuIEVzdGUgZW5mb3F1ZSBwZXJtaXRlIGV2YWx1YXIgc2ltdWx0w6FuZWFtZW50ZSBsYSByb2J1c3RleiBkZSBsYSByZWdsYSB5IGVsIGFwb3J0ZSBtYXJnaW5hbCBkZSB2YXJpYWJsZXMgbWFjcm9lY29uw7NtaWNhcyBhZGljaW9uYWxlcy4NCkxvcyBjb250cm9sZXMgcXVlIGVzdGFyZW1vcyB1c2FuZG8gc29uIGxvcyBzaWd1aWVudGVzOg0KDQotICoqVENVKio6IENhcGFjaXR5IFV0aWxpemF0aW9uOiBUb3RhbCBJbmR1c3RyeSAoUGVyY2VudCBvZiBDYXBhY2l0eSkNCi0gKipVU0dPVlQqKjogQWxsIEVtcGxveWVlczogR292ZXJubWVudCAoVGhvdXNhbmRzIG9mIFBlcnNvbnMpDQotICoqVU5SQVRFKio6IENpdmlsaWFuIFVuZW1wbG95bWVudCBSYXRlIChQZXJjZW50KQ0KLSAqKkRHRFNSRzNRMDg2U0JFQSoqOiBQZXJzb25hbCBjb25zdW1wdGlvbiBleHBlbmRpdHVyZXM6IEdvb2RzIChjaGFpbi10eXBlIHByaWNlIGluZGV4KQ0KLSAqKkdTMTBUQjNNeCoqOiAxMC1ZZWFyIFRyZWFzdXJ5IENvbnN0YW50IE1hdHVyaXR5IE1pbnVzIDMtTW9udGggVHJlYXN1cnkgQmlsbCwgc2Vjb25kYXJ5IG1hcmtldCAoUGVyY2VudCkNCi0gKipDUEYzTVRCM014Kio6IDMtTW9udGggQ29tbWVyY2lhbCBQYXBlciBNaW51cyAzLU1vbnRoIFRyZWFzdXJ5IEJpbGwsIHNlY29uZGFyeSBtYXJrZXQgKFBlcmNlbnQpDQotICoqQk9HTUJBU0VSRUFMeCoqOiBTdC4gTG91aXMgQWRqdXN0ZWQgTW9uZXRhcnkgQmFzZSAoQmlsbGlvbnMgb2YgMTk4Mi04NCBEb2xsYXJzKSwgZGVmbGF0ZWQgYnkgQ1BJDQoNCg0KYGBge3IgY29udHJvbHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfSANCmNvbnRyb2xzIDwtIGMoIlRDVSIsIlVTR09WVCIsIlVOUkFURSIsIkRHRFNSRzNRMDg2U0JFQSIsDQogICAgICAgICAgICAgICAgICAiR1MxMFRCM014IiwiQ1BGM01UQjNNeCIsIkJPR01CQVNFUkVBTHgiKQ0KDQojIEVzdGFuZGFyaXphbW9zIHZhcmlhYmxlcyBkZSBjb250cm9sICANCmRmX3JlZ19zdWIgPC0gZGZfcmVnX3N1YiAlPiUNCiBtdXRhdGUoYWNyb3NzKGFsbF9vZihjb250cm9scyksIH4gYXMubnVtZXJpYyhzY2FsZSgueCkpKSkNCg0KIyBGw7NybXVsYSAgICANCmZvcm1fdjMgPC0gYmYoIEZFREZVTkRTIH4gaV9sYWcxICsgcGlfZ2FwICsgeV9nYXAgKyBUQ1UgKyBVU0dPVlQgKyBVTlJBVEUgKyBER0RTUkczUTA4NlNCRUEgKyBHUzEwVEIzTXggKyBDUEYzTVRCM014ICsgQk9HTUJBU0VSRUFMeCApDQoNCnByaW9yc192MyA8LSBjKA0KICAjIEludGVyY2VwdG8NCiAgcHJpb3Iobm9ybWFsKDAsIDUuMCksIGNsYXNzID0gIkludGVyY2VwdCIpLA0KICANCiAgIyBMQVNTTyBnZW5lcmFsIHBhcmEgdG9kb3MgbG9zIGJldGFzIC0gZXF1aXZhbGUgYSAxL2xhbWJkYSwgYXPDrSBxdWUgc2kgLT4wIG1heW9yIGVzIGxhIHBlbmFsaXphY2nDs24gKHNocmlua2FnZSkNCiAgcHJpb3IoZG91YmxlX2V4cG9uZW50aWFsKDAsIDAuMiksIGNsYXNzID0gImIiKSwNCiAgDQogICMgTsO6Y2xlbyBCSVMgY29uIHByaW9ycyBub3JtYWxlcyBmdWVydGVzDQogIHByaW9yKG5vcm1hbCgwLjc0LCAwLjEwKSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAiaV9sYWcxIiksDQogIHByaW9yKG5vcm1hbCgyLjExLCAwLjEwKSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAicGlfZ2FwIiksDQogIHByaW9yKG5vcm1hbCgwLjI2LCAwLjA1KSwgY2xhc3MgPSAiYiIsIGNvZWYgPSAieV9nYXAiKSwNCiAgDQogICMgU2lnbWEgZMOpYmlsDQogIHByaW9yKHN0dWRlbnRfdCgzLCAwLCAxMCksIGNsYXNzID0gInNpZ21hIikNCikNCg0KIyBBanVzdGUNCnNldC5zZWVkKDQyKQ0KDQp0YXlsb3JfYmF5ZXNfdjNfYnJtcyA8LSBicm0oDQogIGZvcm11bGEgPSBmb3JtX3YzLA0KICBkYXRhICAgID0gZGZfcmVnX3N1YiwNCiAgZmFtaWx5ICA9IGdhdXNzaWFuKCksDQogIHByaW9yICAgPSBwcmlvcnNfdjMsDQogIGNoYWlucyA9IDQsDQogIGl0ZXIgICA9IDE1MDAwLA0KICB3YXJtdXAgPSA1MDAwLA0KICBjb3JlcyAgPSA0LA0KICBzZWVkICAgPSA0MiwNCiAgc2FtcGxlX3ByaW9yID0gInllcyINCikNCmBgYA0KDQpgYGB7ciBjb250cm9sc19zdW1tLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfSANCnN1bW1hcnkodGF5bG9yX2JheWVzX3YzX2JybXMpDQpgYGANCkxhIGVzdGltYWNpw7NuIGJheWVzaWFuYSBjb24gcHJpb3IgTEFTU08gbXVlc3RyYSBxdWUgbG9zIGNvZWZpY2llbnRlcyBwcmluY2lwYWxlcyBkZSBsYSBSZWdsYSBkZSBUYXlsb3IgKGluZXJjaWEsIGJyZWNoYSBkZSBpbmZsYWNpw7NuIHkgb3V0cHV0IGdhcCkgc2UgbWFudGllbmVuIHNpZ25pZmljYXRpdm9zIHkgY29uIG1hZ25pdHVkZXMgY29uc2lzdGVudGVzIGNvbiBsYXMgdmVyc2lvbmVzIGFudGVyaW9yZXMuIEVuIGNhbWJpbywgbGEgbWF5b3LDrWEgZGUgbGFzIHZhcmlhYmxlcyBkZSBjb250cm9sIHByZXNlbnRhbiBkaXN0cmlidWNpb25lcyBwb3N0ZXJpb3JlcyBjZW50cmFkYXMgY2VyY2EgZGUgY2VybyB5IGNvbiBpbnRlcnZhbG9zIGFtcGxpb3MsIGluZGljYW5kbyBxdWUgZWwgc2hyaW5rYWdlIHBlbmFsaXphIGZ1ZXJ0ZW1lbnRlIHN1IGFwb3J0ZSBtYXJnaW5hbC4gU29sbyBHUzEwVEIzTXggbXVlc3RyYSBldmlkZW5jaWEgbW9kZXJhZGEgZGUgZWZlY3RvLiBFbiBjb25qdW50bywgZWwgbW9kZWxvIGNvbmZpcm1hIHF1ZSBsYSBkaW7DoW1pY2EgZGUgdGFzYXMgZXN0w6EgZXhwbGljYWRhIGNhc2kgcG9yIGNvbXBsZXRvIHBvciBsb3MgY29tcG9uZW50ZXMgY2VudHJhbGVzIGRlIGxhIHJlZ2xhLg0KDQojIyBWaXN1YWxpemFjacOzbiBkZSBSZXN1bHRhZG9zICAgIA0KDQpgYGB7ciBjb250cm9sc192aXosIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9IA0KIyBWaXN1YWxpemFjaW9uIGRlIGNvbnRyb2xlcw0KY29udHJvbHNfYiA8LSBjKCJiX1RDVSIsImJfVVNHT1ZUIiwiYl9VTlJBVEUiLCJiX0RHRFNSRzNRMDg2U0JFQSIsDQogICAgICAgICAgICAgICAgImJfR1MxMFRCM014IiwiYl9DUEYzTVRCM014IiwiYl9CT0dNQkFTRVJFQUx4IikNCg0KYXNfZHJhd3NfZGYodGF5bG9yX2JheWVzX3YzX2JybXMpICU+JQ0KICBkcGx5cjo6c2VsZWN0KGFsbF9vZihjb250cm9sc19iKSkgJT4lDQogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksIG5hbWVzX3RvPSJ0ZXJtIiwgdmFsdWVzX3RvPSJ2YWx1ZSIpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9dmFsdWUsIHk9dGVybSkpICsNCiAgc3RhdF9oYWxmZXllKC53aWR0aCA9IDAuOTUpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTAsIGxpbmV0eXBlPSJkYXNoZWQiKSArDQogIGxhYnModGl0bGU9IkNvbnRyb2xlcyBjb24gcHJpb3IgTEFTU086IHBvc3RlcmlvciIsDQogICAgICAgc3VidGl0bGU9IkxvcyBxdWUgcXVlZGFuIGNvbmNlbnRyYWRvcyBlbiAwIG5vIGFwb3J0YW4iLA0KICAgICAgIHg9IkNvZWZpY2llbnRlIiwgeT1OVUxMKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCkVzdGUgZ3LDoWZpY28gbXVlc3RyYSBsYSBkaXN0cmlidWNpw7NuIHBvc3RlcmlvciBkZSBsb3MgY29lZmljaWVudGVzIGFzb2NpYWRvcyBhIGxhcyB2YXJpYWJsZXMgZGUgY29udHJvbCBiYWpvIGVsIHByaW9yIExBU1NPLg0KTGFzIGRpc3RyaWJ1Y2lvbmVzIHF1ZSBxdWVkYW4gY29uY2VudHJhZGFzIGFscmVkZWRvciBkZSBjZXJvIGluZGljYW4gcXVlLCBkYWRvIGVsIHNocmlua2FnZSBhcGxpY2FkbywgZXNhcyB2YXJpYWJsZXMgbm8gYXBvcnRhbiBpbmZvcm1hY2nDs24gcmVsZXZhbnRlLg0KDQpgYGB7ciBsYW1iZGFzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30gDQoNCiMgQ29tcGFyYWNpw7NuIGRlIExhbWJkYXMNCg0KIyBncmlsbGEgZGUgc2NhbGVzIChiKTogZGUgZMOpYmlsIGEgZnVlcnRlDQpiX2dyaWQgPC0gYygxLjAsIDAuNywgMC41LCAwLjMsIDAuMiwgMC4xNSwgMC4xLCAwLjA3LCAwLjA1LCAwLjAyNSkNCg0KIyBGdW5jaW9uIHF1ZSBhcm1hIHByaW9ycyBjb24gY2FkYSBiDQptYWtlX3ByaW9yc192MyA8LSBmdW5jdGlvbihiX3NjYWxlKXsNCiAgDQogIGxhcGxhY2Vfc3RyIDwtIHBhc3RlMCgiZG91YmxlX2V4cG9uZW50aWFsKDAsICIsIGJfc2NhbGUsICIpIikNCiAgDQogIGMoDQogICAgIyBJbnRlcmNlcHRvDQogICAgc2V0X3ByaW9yKCJub3JtYWwoMCwgNS4wKSIsIGNsYXNzID0gIkludGVyY2VwdCIpLA0KICAgIA0KICAgICMgTEFTU08gZ2VuZXJhbCBwYXJhIHRvZG9zIGxvcyBjb2VmaWNpZW50ZXMgYg0KICAgIHNldF9wcmlvcihsYXBsYWNlX3N0ciwgY2xhc3MgPSAiYiIpLA0KICAgIA0KICAgICMgU29icmVzY3JpYm8gbsO6Y2xlbyBCSVMgY29uIG5vcm1hbGVzIGZ1ZXJ0ZXMNCiAgICBzZXRfcHJpb3IoIm5vcm1hbCgwLjc0LCAwLjEwKSIsIGNsYXNzID0gImIiLCBjb2VmID0gImlfbGFnMSIpLA0KICAgIHNldF9wcmlvcigibm9ybWFsKDIuMTEsIDAuMTApIiwgY2xhc3MgPSAiYiIsIGNvZWYgPSAicGlfZ2FwIiksDQogICAgc2V0X3ByaW9yKCJub3JtYWwoMC4yNiwgMC4wNSkiLCBjbGFzcyA9ICJiIiwgY29lZiA9ICJ5X2dhcCIpLA0KICAgIA0KICAgICMgc2lnbWEgZMOpYmlsDQogICAgc2V0X3ByaW9yKCJzdHVkZW50X3QoMywgMCwgMTApIiwgY2xhc3MgPSAic2lnbWEiKQ0KICApDQp9DQoNCg0KIyBSZWVzdGltYXIgbW9kZWxvcyBwYXJhIGNhZGEgYg0KDQpmaXRzX3YzIDwtIG1hcChiX2dyaWQsIH4gYnJtKA0KICBmb3JtdWxhID0gZm9ybV92MywNCiAgZGF0YSAgICA9IGRmX3JlZ19zdWIsDQogIGZhbWlseSAgPSBnYXVzc2lhbigpLA0KICBwcmlvciAgID0gbWFrZV9wcmlvcnNfdjMoLngpLA0KICBjaGFpbnMgID0gNCwNCiAgaXRlciAgICA9IDQwMDAsDQogIHdhcm11cCAgPSAxMDAwLA0KICBjb3JlcyAgID0gNCwNCiAgc2VlZCAgICA9IDQyLA0KICByZWZyZXNoID0gMCANCikpDQoNCg0KbmFtZXMoZml0c192MykgPC0gcGFzdGUwKCJiXyIsIGJfZ3JpZCkNCg0KIyBFeHRyYWVyIGNvZmllY2llbnRlcyBkZSBjb250cm9sZXMgeSBjb25zdHJ1aXIgZWwgcGF0aA0KY29yZV92YXJzIDwtIGMoImlfbGFnMSIsICJwaV9nYXAiLCAieV9nYXAiKQ0KY29yZV9iIDwtIHBhc3RlMCgiYl8iLCBjb3JlX3ZhcnMpDQoNCiMgb2J0aWVuZSBub21icmVzIGJfIHJlYWxlcyBkZXNkZSBjdWFscXVpZXIgZml0IGJybXMNCmdldF9jb250cm9sc19iIDwtIGZ1bmN0aW9uKGZpdCkgew0KICBiX25hbWVzIDwtIGdyZXAoIl5iXyIsIHBvc3Rlcmlvcjo6dmFyaWFibGVzKGFzX2RyYXdzX2RmKGZpdCkpLCB2YWx1ZSA9IFRSVUUpDQogIHNldGRpZmYoYl9uYW1lcywgY29yZV9iKQ0KfQ0KDQpjb250cm9sc19iIDwtIGdldF9jb250cm9sc19iKGZpdHNfdjNbWzFdXSkgICMgdXNhciBlbCBwcmltZXIgZml0IGNvbW8gcmVmZXJlbmNpYQ0KY29udHJvbHNfYg0KDQojIGZ1bmNpw7NuIHBhcmEgZXh0cmFlciBlbCBjb2VmaWNpZW50ZSAibW9kYSIgZGVsIHZlY3Rvcg0KZ2V0X21vZGUgPC0gZnVuY3Rpb24oeCkgew0KICBkIDwtIGRlbnNpdHkoeCkNCiAgZCR4W3doaWNoLm1heChkJHkpXQ0KfQ0KDQoNCnBhdGhzX2RmX21hcCA8LSBtYXAyX2RmcihmaXRzX3YzLCBiX2dyaWQsIH4gew0KICAjIGV4dHJhZXIgZHJhd3MgZGUgbG9zIGNvZWZpY2llbnRlcyBkZSBjb250cm9sZXMNCiAgZHJhd3MgPC0gYXNfZHJhd3NfZGYoLngpICU+JQ0KICAgIGRwbHlyOjpzZWxlY3QoYWxsX29mKGNvbnRyb2xzX2IpKSAlPiUNCiAgICBwaXZvdF9sb25nZXIoZXZlcnl0aGluZygpLCBuYW1lc190bz0idGVybSIsIHZhbHVlc190bz0idmFsdWUiKSAlPiUNCiAgICAjIGV4Y2x1aXIgaW50ZXJjZXB0bw0KICAgIGZpbHRlcih0ZXJtICE9ICJiX0ludGVyY2VwdCIpICU+JQ0KICAgIGdyb3VwX2J5KHRlcm0pICU+JQ0KICAgIHN1bW1hcmlzZSgNCiAgICAgIG1hcCA9IGdldF9tb2RlKHZhbHVlKSwNCiAgICAgIC5ncm91cHM9ImRyb3AiDQogICAgKQ0KICANCiAgZHJhd3MgJT4lDQogICAgbXV0YXRlKA0KICAgICAgYl9zY2FsZSA9IC55LA0KICAgICAgbG9nX2xhbWJkYSA9IGxvZygxLy55KSAgICMgbGFtYmRhIGNsw6FzaWNhID0gMS9iDQogICAgKQ0KfSkNCg0KIyBHcmFmaWNhciBjb2VmaWNpZW50IHBhdGggY29uIE1BUCAoc2luIGludGVyY2VwdG8pDQpnZ3Bsb3QocGF0aHNfZGZfbWFwLCBhZXMoeCA9IGxvZ19sYW1iZGEsIHkgPSBtYXAsIGNvbG9yID0gdGVybSkpICsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDAuOSkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ29lZmljaWVudCBwYXRocyBwYXJhIGNvbnRyb2xlcyAodjMpIiwNCiAgICBzdWJ0aXRsZSA9ICJBIG1heW9yIGxvZyhsYW1iZGEpID0gbWF5b3Igc2hyaW5rYWdlIChiIG3DoXMgY2hpY28pIiwNCiAgICB4ID0gImxvZyhsYW1iZGEpICBbbGFtYmRhID0gMSAvIGJfc2NhbGVdIiwNCiAgICB5ID0gIk1vZGEgcG9zdGVyaW9yIGRlbCBjb2VmaWNpZW50ZSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkNCg0KYGBgDQoNCkVuIGVzdGUgY2Fzbywgc2UgcHVlZGUgdmVyIGPDs21vIGNhbWJpYW4gbG9zIGNvZWZpY2llbnRlcyBkZSBsYXMgdmFyaWFibGVzIGRlIGNvbnRyb2wgYSBtZWRpZGEgcXVlIGF1bWVudGEgbGEgcGVuYWxpemFjacOzbiBMQVNTTy4gQSBtZWRpZGEgcXVlIGVsIHNocmlua2FnZSBzZSBpbnRlbnNpZmljYSwgdG9kb3MgbG9zIGNvZWZpY2llbnRlcyBzZSBjb250cmFlbiBwcm9ncmVzaXZhbWVudGUgaGFjaWEgY2Vyby4gTGFzIHZhcmlhYmxlcyBjdXlvcyBjb2VmaWNpZW50ZXMgY2FlbiByw6FwaWRhbWVudGUgaW5kaWNhbiBtZW5vciByZWxldmFuY2lhIGV4cGxpY2F0aXZhLCBtaWVudHJhcyBxdWUgbGFzIHF1ZSByZXNpc3RlbiBtw6FzIHRpZW1wbyBhbGVqYWRhcyBkZSBjZXJvIHNvbiBsYXMgcXVlIGVsIG1vZGVsbyBjb25zaWRlcmEgcmVsYXRpdmFtZW50ZSBtw6FzIGluZm9ybWF0aXZhcy4NCg0KDQo=